fix(cleanup): comprehensive idempotent cleanup for failed installations
- commit
- 64c80670d71d5bc796411754259b7559e7e1f514
- author
- bnema · · 2025-10-20 03:51 UTC
- committer
- bnema · · 2025-10-20 03:56 UTC
- parent
- 820b598
- signature
- unsigned
4 files · +300 -26
M install.sh +25 -1
| @@ -11,6 +11,30 @@ export ARCHUP_INSTALL_LOG_FILE="/var/log/archup-install.log" | |||
| 11 | 11 | export ARCHUP_REPO_URL="${ARCHUP_REPO_URL:-https://github.com/bnema/archup}" | |
| 12 | 12 | export ARCHUP_RAW_URL="${ARCHUP_RAW_URL:-https://raw.githubusercontent.com/bnema/archup/dev}" | |
| 13 | 13 | ||
| 14 | + | # Handle command-line flags | |
| 15 | + | if [ "$1" = "--cleanup" ]; then | |
| 16 | + | echo "Running cleanup before installation..." | |
| 17 | + | source "$ARCHUP_INSTALL/helpers/cleanup.sh" default | |
| 18 | + | fi | |
| 19 | + | ||
| 20 | + | if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then | |
| 21 | + | cat << 'HELP' | |
| 22 | + | Usage: install.sh [OPTIONS] | |
| 23 | + | ||
| 24 | + | OPTIONS: | |
| 25 | + | --cleanup Cleanup before running installation | |
| 26 | + | -h, --help Show this help message | |
| 27 | + | ||
| 28 | + | EXAMPLES: | |
| 29 | + | install.sh # Run normal installation | |
| 30 | + | install.sh --cleanup # Cleanup then run installation | |
| 31 | + | ./cleanup.sh default # Manual cleanup only | |
| 32 | + | ./cleanup.sh full # Full cleanup including /mnt wipe | |
| 33 | + | ./cleanup.sh diagnostic # Show current system state | |
| 34 | + | HELP | |
| 35 | + | exit 0 | |
| 36 | + | fi | |
| 37 | + | ||
| 14 | 38 | # Download installer files if not present (for curl-based installation) | |
| 15 | 39 | if [ ! -d "$ARCHUP_INSTALL" ]; then | |
| 16 | 40 | echo "=== Downloading ArchUp installer files ===" | |
| @@ -27,7 +51,7 @@ if [ ! -d "$ARCHUP_INSTALL" ]; then | |||
| 27 | 51 | curl -sL "$GITHUB_RAW/logo.txt" -o "$ARCHUP_PATH/logo.txt" | |
| 28 | 52 | ||
| 29 | 53 | echo "Downloading helpers..." | |
| 30 | - | for file in all.sh logging.sh errors.sh presentation.sh chroot.sh; do | |
| 54 | + | for file in all.sh logging.sh errors.sh presentation.sh chroot.sh cleanup.sh; do | |
| 31 | 55 | curl -sL "$GITHUB_RAW/install/helpers/$file" -o "$ARCHUP_INSTALL/helpers/$file" | |
| 32 | 56 | done | |
| 33 | 57 | ||
| @@ -11,6 +11,30 @@ export ARCHUP_INSTALL_LOG_FILE="/var/log/archup-install.log" | |||||
| 11 | export ARCHUP_REPO_URL="${ARCHUP_REPO_URL:-https://github.com/bnema/archup}" | 11 | export ARCHUP_REPO_URL="${ARCHUP_REPO_URL:-https://github.com/bnema/archup}" | ||
| 12 | export ARCHUP_RAW_URL="${ARCHUP_RAW_URL:-https://raw.githubusercontent.com/bnema/archup/dev}" | 12 | export ARCHUP_RAW_URL="${ARCHUP_RAW_URL:-https://raw.githubusercontent.com/bnema/archup/dev}" | ||
| 13 | 13 | ||||
| 14 | + | # Handle command-line flags | |||
| 15 | + | if [ "$1" = "--cleanup" ]; then | |||
| 16 | + | echo "Running cleanup before installation..." | |||
| 17 | + | source "$ARCHUP_INSTALL/helpers/cleanup.sh" default | |||
| 18 | + | fi | |||
| 19 | + | ||||
| 20 | + | if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then | |||
| 21 | + | cat << 'HELP' | |||
| 22 | + | Usage: install.sh [OPTIONS] | |||
| 23 | + | ||||
| 24 | + | OPTIONS: | |||
| 25 | + | --cleanup Cleanup before running installation | |||
| 26 | + | -h, --help Show this help message | |||
| 27 | + | ||||
| 28 | + | EXAMPLES: | |||
| 29 | + | install.sh # Run normal installation | |||
| 30 | + | install.sh --cleanup # Cleanup then run installation | |||
| 31 | + | ./cleanup.sh default # Manual cleanup only | |||
| 32 | + | ./cleanup.sh full # Full cleanup including /mnt wipe | |||
| 33 | + | ./cleanup.sh diagnostic # Show current system state | |||
| 34 | + | HELP | |||
| 35 | + | exit 0 | |||
| 36 | + | fi | |||
| 37 | + | ||||
| 14 | # Download installer files if not present (for curl-based installation) | 38 | # Download installer files if not present (for curl-based installation) | ||
| 15 | if [ ! -d "$ARCHUP_INSTALL" ]; then | 39 | if [ ! -d "$ARCHUP_INSTALL" ]; then | ||
| 16 | echo "=== Downloading ArchUp installer files ===" | 40 | echo "=== Downloading ArchUp installer files ===" | ||
| @@ -27,7 +51,7 @@ if [ ! -d "$ARCHUP_INSTALL" ]; then | |||||
| 27 | curl -sL "$GITHUB_RAW/logo.txt" -o "$ARCHUP_PATH/logo.txt" | 51 | curl -sL "$GITHUB_RAW/logo.txt" -o "$ARCHUP_PATH/logo.txt" | ||
| 28 | 52 | ||||
| 29 | echo "Downloading helpers..." | 53 | echo "Downloading helpers..." | ||
| 30 | - | for file in all.sh logging.sh errors.sh presentation.sh chroot.sh; do | 54 | + | for file in all.sh logging.sh errors.sh presentation.sh chroot.sh cleanup.sh; do |
| 31 | curl -sL "$GITHUB_RAW/install/helpers/$file" -o "$ARCHUP_INSTALL/helpers/$file" | 55 | curl -sL "$GITHUB_RAW/install/helpers/$file" -o "$ARCHUP_INSTALL/helpers/$file" | ||
| 32 | done | 56 | done | ||
| 33 | 57 | ||||
M install/bootstrap.sh +0 -21
| @@ -5,27 +5,6 @@ | |||
| 5 | 5 | ||
| 6 | 6 | set -e | |
| 7 | 7 | ||
| 8 | - | # Clean up from previous installation attempts | |
| 9 | - | echo "Cleaning up previous installation attempts..." | |
| 10 | - | ||
| 11 | - | # Unmount all /mnt mountpoints (recursive) | |
| 12 | - | if mountpoint -q /mnt 2>/dev/null; then | |
| 13 | - | echo "Unmounting /mnt..." | |
| 14 | - | umount -R /mnt 2>/dev/null || true | |
| 15 | - | fi | |
| 16 | - | ||
| 17 | - | # Close any open LUKS containers | |
| 18 | - | if [ -e /dev/mapper/cryptroot ]; then | |
| 19 | - | echo "Closing LUKS container..." | |
| 20 | - | cryptsetup close cryptroot 2>/dev/null || true | |
| 21 | - | fi | |
| 22 | - | ||
| 23 | - | # Deactivate swap | |
| 24 | - | swapoff -a 2>/dev/null || true | |
| 25 | - | ||
| 26 | - | echo "[OK] Cleanup complete" | |
| 27 | - | echo | |
| 28 | - | ||
| 29 | 8 | # Clean up old log file to ensure fresh logs for this attempt | |
| 30 | 9 | if [ -f "$ARCHUP_INSTALL_LOG_FILE" ]; then | |
| 31 | 10 | rm -f "$ARCHUP_INSTALL_LOG_FILE" | |
| @@ -5,27 +5,6 @@ | |||||
| 5 | 5 | ||||
| 6 | set -e | 6 | set -e | ||
| 7 | 7 | ||||
| 8 | - | # Clean up from previous installation attempts | |||
| 9 | - | echo "Cleaning up previous installation attempts..." | |||
| 10 | - | ||||
| 11 | - | # Unmount all /mnt mountpoints (recursive) | |||
| 12 | - | if mountpoint -q /mnt 2>/dev/null; then | |||
| 13 | - | echo "Unmounting /mnt..." | |||
| 14 | - | umount -R /mnt 2>/dev/null || true | |||
| 15 | - | fi | |||
| 16 | - | ||||
| 17 | - | # Close any open LUKS containers | |||
| 18 | - | if [ -e /dev/mapper/cryptroot ]; then | |||
| 19 | - | echo "Closing LUKS container..." | |||
| 20 | - | cryptsetup close cryptroot 2>/dev/null || true | |||
| 21 | - | fi | |||
| 22 | - | ||||
| 23 | - | # Deactivate swap | |||
| 24 | - | swapoff -a 2>/dev/null || true | |||
| 25 | - | ||||
| 26 | - | echo "[OK] Cleanup complete" | |||
| 27 | - | echo | |||
| 28 | - | ||||
| 29 | # Clean up old log file to ensure fresh logs for this attempt | 8 | # Clean up old log file to ensure fresh logs for this attempt | ||
| 30 | if [ -f "$ARCHUP_INSTALL_LOG_FILE" ]; then | 9 | if [ -f "$ARCHUP_INSTALL_LOG_FILE" ]; then | ||
| 31 | rm -f "$ARCHUP_INSTALL_LOG_FILE" | 10 | rm -f "$ARCHUP_INSTALL_LOG_FILE" | ||
A install/helpers/cleanup.sh +275 -0
| @@ -0,0 +1,275 @@ | |||
| 1 | + | #!/bin/bash | |
| 2 | + | # ArchUp Cleanup - Remove artifacts from failed installations | |
| 3 | + | # This script is 100% idempotent and safe to call multiple times | |
| 4 | + | # Called from bootstrap.sh on every install attempt | |
| 5 | + | ||
| 6 | + | # Cleanup modes: | |
| 7 | + | # - default (called from bootstrap): Unmount, close LUKS, disable swap | |
| 8 | + | # - full (optional): Also delete /mnt content, allow fresh pacstrap | |
| 9 | + | # - efi-cleanup (optional): Remove UEFI boot entries (manual only) | |
| 10 | + | ||
| 11 | + | set +e # Continue even if commands fail | |
| 12 | + | ||
| 13 | + | CLEANUP_MODE="${1:-default}" | |
| 14 | + | ||
| 15 | + | # Color codes for output | |
| 16 | + | RED='\033[0;31m' | |
| 17 | + | GREEN='\033[0;32m' | |
| 18 | + | YELLOW='\033[0;33m' | |
| 19 | + | NC='\033[0m' # No Color | |
| 20 | + | ||
| 21 | + | log_cleanup() { | |
| 22 | + | echo "[CLEANUP] $1" | |
| 23 | + | if [ -n "${ARCHUP_INSTALL_LOG_FILE:-}" ] && [ -f "$ARCHUP_INSTALL_LOG_FILE" ]; then | |
| 24 | + | echo "[$(date '+%Y-%m-%d %H:%M:%S')] [CLEANUP] $1" >> "$ARCHUP_INSTALL_LOG_FILE" | |
| 25 | + | fi | |
| 26 | + | } | |
| 27 | + | ||
| 28 | + | log_success() { | |
| 29 | + | echo -e "${GREEN}[CLEANUP OK]${NC} $1" | |
| 30 | + | if [ -n "${ARCHUP_INSTALL_LOG_FILE:-}" ] && [ -f "$ARCHUP_INSTALL_LOG_FILE" ]; then | |
| 31 | + | echo "[$(date '+%Y-%m-%d %H:%M:%S')] [CLEANUP OK] $1" >> "$ARCHUP_INSTALL_LOG_FILE" | |
| 32 | + | fi | |
| 33 | + | } | |
| 34 | + | ||
| 35 | + | log_error() { | |
| 36 | + | echo -e "${RED}[CLEANUP ERROR]${NC} $1" | |
| 37 | + | if [ -n "${ARCHUP_INSTALL_LOG_FILE:-}" ] && [ -f "$ARCHUP_INSTALL_LOG_FILE" ]; then | |
| 38 | + | echo "[$(date '+%Y-%m-%d %H:%M:%S')] [CLEANUP ERROR] $1" >> "$ARCHUP_INSTALL_LOG_FILE" | |
| 39 | + | fi | |
| 40 | + | } | |
| 41 | + | ||
| 42 | + | # ============================================================ | |
| 43 | + | # PHASE 1: SAFE UNMOUNTING - Always safe to do | |
| 44 | + | # ============================================================ | |
| 45 | + | ||
| 46 | + | cleanup_mounts() { | |
| 47 | + | log_cleanup "Cleaning up mounted filesystems..." | |
| 48 | + | ||
| 49 | + | # Unmount in reverse order (most specific first) | |
| 50 | + | local mounts_to_clean=( | |
| 51 | + | "/mnt/boot" | |
| 52 | + | "/mnt/home" | |
| 53 | + | "/mnt" | |
| 54 | + | ) | |
| 55 | + | ||
| 56 | + | for mount_point in "${mounts_to_clean[@]}"; do | |
| 57 | + | if mountpoint -q "$mount_point" 2>/dev/null; then | |
| 58 | + | log_cleanup "Unmounting $mount_point..." | |
| 59 | + | if umount -R "$mount_point" 2>/dev/null; then | |
| 60 | + | log_success "Unmounted $mount_point" | |
| 61 | + | else | |
| 62 | + | # Force unmount if normal unmount fails | |
| 63 | + | log_cleanup "Force unmounting $mount_point..." | |
| 64 | + | if umount -R -l "$mount_point" 2>/dev/null; then | |
| 65 | + | log_success "Force unmounted $mount_point" | |
| 66 | + | else | |
| 67 | + | log_error "Failed to unmount $mount_point (may retry later)" | |
| 68 | + | fi | |
| 69 | + | fi | |
| 70 | + | fi | |
| 71 | + | done | |
| 72 | + | ||
| 73 | + | # Wait for any lingering unmount operations | |
| 74 | + | sleep 1 | |
| 75 | + | } | |
| 76 | + | ||
| 77 | + | # ============================================================ | |
| 78 | + | # PHASE 2: CLOSE ENCRYPTION - Always safe to do | |
| 79 | + | # ============================================================ | |
| 80 | + | ||
| 81 | + | cleanup_encryption() { | |
| 82 | + | log_cleanup "Cleaning up LUKS/dm-crypt mappings..." | |
| 83 | + | ||
| 84 | + | # Close cryptroot specifically (Omarchy convention) | |
| 85 | + | if [ -e /dev/mapper/cryptroot ]; then | |
| 86 | + | log_cleanup "Closing LUKS container: cryptroot..." | |
| 87 | + | if cryptsetup close cryptroot 2>/dev/null; then | |
| 88 | + | log_success "Closed cryptroot" | |
| 89 | + | else | |
| 90 | + | log_error "Failed to close cryptroot" | |
| 91 | + | fi | |
| 92 | + | fi | |
| 93 | + | ||
| 94 | + | # Close ALL dm-crypt mappings (in case multiple exist) | |
| 95 | + | local crypt_mappings=$(dmsetup ls --target crypt 2>/dev/null | cut -f1) | |
| 96 | + | if [ -n "$crypt_mappings" ]; then | |
| 97 | + | while IFS= read -r mapping; do | |
| 98 | + | if [ -n "$mapping" ]; then | |
| 99 | + | log_cleanup "Closing dm-crypt mapping: $mapping..." | |
| 100 | + | if cryptsetup close "$mapping" 2>/dev/null; then | |
| 101 | + | log_success "Closed dm-crypt mapping: $mapping" | |
| 102 | + | else | |
| 103 | + | log_error "Failed to close $mapping" | |
| 104 | + | fi | |
| 105 | + | fi | |
| 106 | + | done <<< "$crypt_mappings" | |
| 107 | + | fi | |
| 108 | + | ||
| 109 | + | # Ensure all device mapper entries are removed | |
| 110 | + | if command -v dmsetup &>/dev/null; then | |
| 111 | + | if dmsetup table 2>/dev/null | grep -q crypt; then | |
| 112 | + | log_cleanup "Removing lingering device mapper entries..." | |
| 113 | + | dmsetup remove_all 2>/dev/null || true | |
| 114 | + | log_success "Device mapper cleanup attempted" | |
| 115 | + | fi | |
| 116 | + | fi | |
| 117 | + | } | |
| 118 | + | ||
| 119 | + | # ============================================================ | |
| 120 | + | # PHASE 3: DISABLE SWAP - Always safe to do | |
| 121 | + | # ============================================================ | |
| 122 | + | ||
| 123 | + | cleanup_swap() { | |
| 124 | + | log_cleanup "Disabling swap..." | |
| 125 | + | ||
| 126 | + | if swapon --show 2>/dev/null | grep -q .; then | |
| 127 | + | log_cleanup "Found active swap, disabling..." | |
| 128 | + | if swapoff -a 2>/dev/null; then | |
| 129 | + | log_success "Swap disabled" | |
| 130 | + | else | |
| 131 | + | log_error "Failed to disable swap (non-critical)" | |
| 132 | + | fi | |
| 133 | + | fi | |
| 134 | + | } | |
| 135 | + | ||
| 136 | + | # ============================================================ | |
| 137 | + | # PHASE 4: KILL STUCK PROCESSES - Always safe to do | |
| 138 | + | # ============================================================ | |
| 139 | + | ||
| 140 | + | cleanup_processes() { | |
| 141 | + | log_cleanup "Checking for stuck pacstrap/chroot processes..." | |
| 142 | + | ||
| 143 | + | # Kill any stuck pacstrap or arch-chroot processes | |
| 144 | + | local stuck_pids=$(pgrep -f "pacstrap|arch-chroot" 2>/dev/null) | |
| 145 | + | if [ -n "$stuck_pids" ]; then | |
| 146 | + | log_cleanup "Killing stuck processes: $stuck_pids" | |
| 147 | + | kill $stuck_pids 2>/dev/null || true | |
| 148 | + | sleep 1 | |
| 149 | + | kill -9 $stuck_pids 2>/dev/null || true | |
| 150 | + | log_success "Cleaned up stuck processes" | |
| 151 | + | fi | |
| 152 | + | } | |
| 153 | + | ||
| 154 | + | # ============================================================ | |
| 155 | + | # PHASE 5: FILESYSTEM SYNC - Always safe to do | |
| 156 | + | # ============================================================ | |
| 157 | + | ||
| 158 | + | cleanup_sync() { | |
| 159 | + | log_cleanup "Syncing filesystems..." | |
| 160 | + | ||
| 161 | + | if sync 2>/dev/null; then | |
| 162 | + | log_success "Filesystems synced" | |
| 163 | + | else | |
| 164 | + | log_error "Failed to sync filesystems (non-critical)" | |
| 165 | + | fi | |
| 166 | + | } | |
| 167 | + | ||
| 168 | + | # ============================================================ | |
| 169 | + | # OPTIONAL: FULL CLEANUP - Wipe /mnt (use --full flag) | |
| 170 | + | # ============================================================ | |
| 171 | + | ||
| 172 | + | cleanup_full() { | |
| 173 | + | log_cleanup "Performing FULL cleanup - deleting /mnt content..." | |
| 174 | + | ||
| 175 | + | if [ -d /mnt ]; then | |
| 176 | + | log_cleanup "Removing all files and directories in /mnt..." | |
| 177 | + | if rm -rf /mnt/* 2>/dev/null; then | |
| 178 | + | log_success "Removed /mnt content" | |
| 179 | + | else | |
| 180 | + | # Try alternate approach | |
| 181 | + | log_cleanup "Retry: Using find to remove /mnt content..." | |
| 182 | + | find /mnt -mindepth 1 -delete 2>/dev/null || true | |
| 183 | + | log_success "Removed /mnt content (with find)" | |
| 184 | + | fi | |
| 185 | + | fi | |
| 186 | + | ||
| 187 | + | # Ensure /mnt directory exists for next installation | |
| 188 | + | mkdir -p /mnt 2>/dev/null || true | |
| 189 | + | log_success "Prepared /mnt for fresh installation" | |
| 190 | + | } | |
| 191 | + | ||
| 192 | + | # ============================================================ | |
| 193 | + | # OPTIONAL: UEFI BOOT ENTRY CLEANUP (advanced/manual only) | |
| 194 | + | # ============================================================ | |
| 195 | + | ||
| 196 | + | cleanup_uefi_entries() { | |
| 197 | + | log_cleanup "Listing existing UEFI boot entries..." | |
| 198 | + | echo | |
| 199 | + | echo "Current UEFI boot entries:" | |
| 200 | + | efibootmgr 2>/dev/null || log_error "efibootmgr not available" | |
| 201 | + | echo | |
| 202 | + | echo "To remove archup entries, run:" | |
| 203 | + | echo " efibootmgr -b XXXX -B (where XXXX is the entry number)" | |
| 204 | + | echo | |
| 205 | + | log_cleanup "UEFI cleanup requires manual intervention" | |
| 206 | + | } | |
| 207 | + | ||
| 208 | + | # ============================================================ | |
| 209 | + | # DIAGNOSTIC: Check current state | |
| 210 | + | # ============================================================ | |
| 211 | + | ||
| 212 | + | cleanup_diagnostic() { | |
| 213 | + | log_cleanup "=== SYSTEM STATE DIAGNOSTIC ===" | |
| 214 | + | ||
| 215 | + | echo "Mounted filesystems at /mnt:" | |
| 216 | + | mount | grep /mnt || echo " (none)" | |
| 217 | + | echo | |
| 218 | + | ||
| 219 | + | echo "Active dm-crypt mappings:" | |
| 220 | + | dmsetup ls --target crypt 2>/dev/null || echo " (none)" | |
| 221 | + | echo | |
| 222 | + | ||
| 223 | + | echo "Active swap:" | |
| 224 | + | swapon --show 2>/dev/null || echo " (none)" | |
| 225 | + | echo | |
| 226 | + | ||
| 227 | + | echo "Partitions:" | |
| 228 | + | lsblk 2>/dev/null | head -20 | |
| 229 | + | } | |
| 230 | + | ||
| 231 | + | # ============================================================ | |
| 232 | + | # MAIN EXECUTION | |
| 233 | + | # ============================================================ | |
| 234 | + | ||
| 235 | + | case "$CLEANUP_MODE" in | |
| 236 | + | default) | |
| 237 | + | log_cleanup "=== ArchUp Cleanup (DEFAULT) ===" | |
| 238 | + | cleanup_mounts | |
| 239 | + | cleanup_encryption | |
| 240 | + | cleanup_swap | |
| 241 | + | cleanup_processes | |
| 242 | + | cleanup_sync | |
| 243 | + | log_success "=== Default cleanup complete ===" | |
| 244 | + | ;; | |
| 245 | + | ||
| 246 | + | full) | |
| 247 | + | log_cleanup "=== ArchUp Cleanup (FULL - DESTRUCTIVE) ===" | |
| 248 | + | cleanup_mounts | |
| 249 | + | cleanup_encryption | |
| 250 | + | cleanup_swap | |
| 251 | + | cleanup_processes | |
| 252 | + | cleanup_full | |
| 253 | + | cleanup_sync | |
| 254 | + | log_success "=== Full cleanup complete ===" | |
| 255 | + | ;; | |
| 256 | + | ||
| 257 | + | uefi-cleanup) | |
| 258 | + | cleanup_uefi_entries | |
| 259 | + | ;; | |
| 260 | + | ||
| 261 | + | diagnostic) | |
| 262 | + | cleanup_diagnostic | |
| 263 | + | ;; | |
| 264 | + | ||
| 265 | + | *) | |
| 266 | + | echo "Usage: cleanup.sh [default|full|uefi-cleanup|diagnostic]" | |
| 267 | + | echo "" | |
| 268 | + | echo "Modes:" | |
| 269 | + | echo " default - Unmount, close LUKS, disable swap (safe, always done)" | |
| 270 | + | echo " full - Also delete /mnt content (destructive)" | |
| 271 | + | echo " uefi-cleanup - Show UEFI boot entries (manual cleanup)" | |
| 272 | + | echo " diagnostic - Show current system state" | |
| 273 | + | exit 1 | |
| 274 | + | ;; | |
| 275 | + | esac | |
| @@ -0,0 +1,275 @@ | |||||
| 1 | + | #!/bin/bash | |||
| 2 | + | # ArchUp Cleanup - Remove artifacts from failed installations | |||
| 3 | + | # This script is 100% idempotent and safe to call multiple times | |||
| 4 | + | # Called from bootstrap.sh on every install attempt | |||
| 5 | + | ||||
| 6 | + | # Cleanup modes: | |||
| 7 | + | # - default (called from bootstrap): Unmount, close LUKS, disable swap | |||
| 8 | + | # - full (optional): Also delete /mnt content, allow fresh pacstrap | |||
| 9 | + | # - efi-cleanup (optional): Remove UEFI boot entries (manual only) | |||
| 10 | + | ||||
| 11 | + | set +e # Continue even if commands fail | |||
| 12 | + | ||||
| 13 | + | CLEANUP_MODE="${1:-default}" | |||
| 14 | + | ||||
| 15 | + | # Color codes for output | |||
| 16 | + | RED='\033[0;31m' | |||
| 17 | + | GREEN='\033[0;32m' | |||
| 18 | + | YELLOW='\033[0;33m' | |||
| 19 | + | NC='\033[0m' # No Color | |||
| 20 | + | ||||
| 21 | + | log_cleanup() { | |||
| 22 | + | echo "[CLEANUP] $1" | |||
| 23 | + | if [ -n "${ARCHUP_INSTALL_LOG_FILE:-}" ] && [ -f "$ARCHUP_INSTALL_LOG_FILE" ]; then | |||
| 24 | + | echo "[$(date '+%Y-%m-%d %H:%M:%S')] [CLEANUP] $1" >> "$ARCHUP_INSTALL_LOG_FILE" | |||
| 25 | + | fi | |||
| 26 | + | } | |||
| 27 | + | ||||
| 28 | + | log_success() { | |||
| 29 | + | echo -e "${GREEN}[CLEANUP OK]${NC} $1" | |||
| 30 | + | if [ -n "${ARCHUP_INSTALL_LOG_FILE:-}" ] && [ -f "$ARCHUP_INSTALL_LOG_FILE" ]; then | |||
| 31 | + | echo "[$(date '+%Y-%m-%d %H:%M:%S')] [CLEANUP OK] $1" >> "$ARCHUP_INSTALL_LOG_FILE" | |||
| 32 | + | fi | |||
| 33 | + | } | |||
| 34 | + | ||||
| 35 | + | log_error() { | |||
| 36 | + | echo -e "${RED}[CLEANUP ERROR]${NC} $1" | |||
| 37 | + | if [ -n "${ARCHUP_INSTALL_LOG_FILE:-}" ] && [ -f "$ARCHUP_INSTALL_LOG_FILE" ]; then | |||
| 38 | + | echo "[$(date '+%Y-%m-%d %H:%M:%S')] [CLEANUP ERROR] $1" >> "$ARCHUP_INSTALL_LOG_FILE" | |||
| 39 | + | fi | |||
| 40 | + | } | |||
| 41 | + | ||||
| 42 | + | # ============================================================ | |||
| 43 | + | # PHASE 1: SAFE UNMOUNTING - Always safe to do | |||
| 44 | + | # ============================================================ | |||
| 45 | + | ||||
| 46 | + | cleanup_mounts() { | |||
| 47 | + | log_cleanup "Cleaning up mounted filesystems..." | |||
| 48 | + | ||||
| 49 | + | # Unmount in reverse order (most specific first) | |||
| 50 | + | local mounts_to_clean=( | |||
| 51 | + | "/mnt/boot" | |||
| 52 | + | "/mnt/home" | |||
| 53 | + | "/mnt" | |||
| 54 | + | ) | |||
| 55 | + | ||||
| 56 | + | for mount_point in "${mounts_to_clean[@]}"; do | |||
| 57 | + | if mountpoint -q "$mount_point" 2>/dev/null; then | |||
| 58 | + | log_cleanup "Unmounting $mount_point..." | |||
| 59 | + | if umount -R "$mount_point" 2>/dev/null; then | |||
| 60 | + | log_success "Unmounted $mount_point" | |||
| 61 | + | else | |||
| 62 | + | # Force unmount if normal unmount fails | |||
| 63 | + | log_cleanup "Force unmounting $mount_point..." | |||
| 64 | + | if umount -R -l "$mount_point" 2>/dev/null; then | |||
| 65 | + | log_success "Force unmounted $mount_point" | |||
| 66 | + | else | |||
| 67 | + | log_error "Failed to unmount $mount_point (may retry later)" | |||
| 68 | + | fi | |||
| 69 | + | fi | |||
| 70 | + | fi | |||
| 71 | + | done | |||
| 72 | + | ||||
| 73 | + | # Wait for any lingering unmount operations | |||
| 74 | + | sleep 1 | |||
| 75 | + | } | |||
| 76 | + | ||||
| 77 | + | # ============================================================ | |||
| 78 | + | # PHASE 2: CLOSE ENCRYPTION - Always safe to do | |||
| 79 | + | # ============================================================ | |||
| 80 | + | ||||
| 81 | + | cleanup_encryption() { | |||
| 82 | + | log_cleanup "Cleaning up LUKS/dm-crypt mappings..." | |||
| 83 | + | ||||
| 84 | + | # Close cryptroot specifically (Omarchy convention) | |||
| 85 | + | if [ -e /dev/mapper/cryptroot ]; then | |||
| 86 | + | log_cleanup "Closing LUKS container: cryptroot..." | |||
| 87 | + | if cryptsetup close cryptroot 2>/dev/null; then | |||
| 88 | + | log_success "Closed cryptroot" | |||
| 89 | + | else | |||
| 90 | + | log_error "Failed to close cryptroot" | |||
| 91 | + | fi | |||
| 92 | + | fi | |||
| 93 | + | ||||
| 94 | + | # Close ALL dm-crypt mappings (in case multiple exist) | |||
| 95 | + | local crypt_mappings=$(dmsetup ls --target crypt 2>/dev/null | cut -f1) | |||
| 96 | + | if [ -n "$crypt_mappings" ]; then | |||
| 97 | + | while IFS= read -r mapping; do | |||
| 98 | + | if [ -n "$mapping" ]; then | |||
| 99 | + | log_cleanup "Closing dm-crypt mapping: $mapping..." | |||
| 100 | + | if cryptsetup close "$mapping" 2>/dev/null; then | |||
| 101 | + | log_success "Closed dm-crypt mapping: $mapping" | |||
| 102 | + | else | |||
| 103 | + | log_error "Failed to close $mapping" | |||
| 104 | + | fi | |||
| 105 | + | fi | |||
| 106 | + | done <<< "$crypt_mappings" | |||
| 107 | + | fi | |||
| 108 | + | ||||
| 109 | + | # Ensure all device mapper entries are removed | |||
| 110 | + | if command -v dmsetup &>/dev/null; then | |||
| 111 | + | if dmsetup table 2>/dev/null | grep -q crypt; then | |||
| 112 | + | log_cleanup "Removing lingering device mapper entries..." | |||
| 113 | + | dmsetup remove_all 2>/dev/null || true | |||
| 114 | + | log_success "Device mapper cleanup attempted" | |||
| 115 | + | fi | |||
| 116 | + | fi | |||
| 117 | + | } | |||
| 118 | + | ||||
| 119 | + | # ============================================================ | |||
| 120 | + | # PHASE 3: DISABLE SWAP - Always safe to do | |||
| 121 | + | # ============================================================ | |||
| 122 | + | ||||
| 123 | + | cleanup_swap() { | |||
| 124 | + | log_cleanup "Disabling swap..." | |||
| 125 | + | ||||
| 126 | + | if swapon --show 2>/dev/null | grep -q .; then | |||
| 127 | + | log_cleanup "Found active swap, disabling..." | |||
| 128 | + | if swapoff -a 2>/dev/null; then | |||
| 129 | + | log_success "Swap disabled" | |||
| 130 | + | else | |||
| 131 | + | log_error "Failed to disable swap (non-critical)" | |||
| 132 | + | fi | |||
| 133 | + | fi | |||
| 134 | + | } | |||
| 135 | + | ||||
| 136 | + | # ============================================================ | |||
| 137 | + | # PHASE 4: KILL STUCK PROCESSES - Always safe to do | |||
| 138 | + | # ============================================================ | |||
| 139 | + | ||||
| 140 | + | cleanup_processes() { | |||
| 141 | + | log_cleanup "Checking for stuck pacstrap/chroot processes..." | |||
| 142 | + | ||||
| 143 | + | # Kill any stuck pacstrap or arch-chroot processes | |||
| 144 | + | local stuck_pids=$(pgrep -f "pacstrap|arch-chroot" 2>/dev/null) | |||
| 145 | + | if [ -n "$stuck_pids" ]; then | |||
| 146 | + | log_cleanup "Killing stuck processes: $stuck_pids" | |||
| 147 | + | kill $stuck_pids 2>/dev/null || true | |||
| 148 | + | sleep 1 | |||
| 149 | + | kill -9 $stuck_pids 2>/dev/null || true | |||
| 150 | + | log_success "Cleaned up stuck processes" | |||
| 151 | + | fi | |||
| 152 | + | } | |||
| 153 | + | ||||
| 154 | + | # ============================================================ | |||
| 155 | + | # PHASE 5: FILESYSTEM SYNC - Always safe to do | |||
| 156 | + | # ============================================================ | |||
| 157 | + | ||||
| 158 | + | cleanup_sync() { | |||
| 159 | + | log_cleanup "Syncing filesystems..." | |||
| 160 | + | ||||
| 161 | + | if sync 2>/dev/null; then | |||
| 162 | + | log_success "Filesystems synced" | |||
| 163 | + | else | |||
| 164 | + | log_error "Failed to sync filesystems (non-critical)" | |||
| 165 | + | fi | |||
| 166 | + | } | |||
| 167 | + | ||||
| 168 | + | # ============================================================ | |||
| 169 | + | # OPTIONAL: FULL CLEANUP - Wipe /mnt (use --full flag) | |||
| 170 | + | # ============================================================ | |||
| 171 | + | ||||
| 172 | + | cleanup_full() { | |||
| 173 | + | log_cleanup "Performing FULL cleanup - deleting /mnt content..." | |||
| 174 | + | ||||
| 175 | + | if [ -d /mnt ]; then | |||
| 176 | + | log_cleanup "Removing all files and directories in /mnt..." | |||
| 177 | + | if rm -rf /mnt/* 2>/dev/null; then | |||
| 178 | + | log_success "Removed /mnt content" | |||
| 179 | + | else | |||
| 180 | + | # Try alternate approach | |||
| 181 | + | log_cleanup "Retry: Using find to remove /mnt content..." | |||
| 182 | + | find /mnt -mindepth 1 -delete 2>/dev/null || true | |||
| 183 | + | log_success "Removed /mnt content (with find)" | |||
| 184 | + | fi | |||
| 185 | + | fi | |||
| 186 | + | ||||
| 187 | + | # Ensure /mnt directory exists for next installation | |||
| 188 | + | mkdir -p /mnt 2>/dev/null || true | |||
| 189 | + | log_success "Prepared /mnt for fresh installation" | |||
| 190 | + | } | |||
| 191 | + | ||||
| 192 | + | # ============================================================ | |||
| 193 | + | # OPTIONAL: UEFI BOOT ENTRY CLEANUP (advanced/manual only) | |||
| 194 | + | # ============================================================ | |||
| 195 | + | ||||
| 196 | + | cleanup_uefi_entries() { | |||
| 197 | + | log_cleanup "Listing existing UEFI boot entries..." | |||
| 198 | + | echo | |||
| 199 | + | echo "Current UEFI boot entries:" | |||
| 200 | + | efibootmgr 2>/dev/null || log_error "efibootmgr not available" | |||
| 201 | + | echo | |||
| 202 | + | echo "To remove archup entries, run:" | |||
| 203 | + | echo " efibootmgr -b XXXX -B (where XXXX is the entry number)" | |||
| 204 | + | echo | |||
| 205 | + | log_cleanup "UEFI cleanup requires manual intervention" | |||
| 206 | + | } | |||
| 207 | + | ||||
| 208 | + | # ============================================================ | |||
| 209 | + | # DIAGNOSTIC: Check current state | |||
| 210 | + | # ============================================================ | |||
| 211 | + | ||||
| 212 | + | cleanup_diagnostic() { | |||
| 213 | + | log_cleanup "=== SYSTEM STATE DIAGNOSTIC ===" | |||
| 214 | + | ||||
| 215 | + | echo "Mounted filesystems at /mnt:" | |||
| 216 | + | mount | grep /mnt || echo " (none)" | |||
| 217 | + | echo | |||
| 218 | + | ||||
| 219 | + | echo "Active dm-crypt mappings:" | |||
| 220 | + | dmsetup ls --target crypt 2>/dev/null || echo " (none)" | |||
| 221 | + | echo | |||
| 222 | + | ||||
| 223 | + | echo "Active swap:" | |||
| 224 | + | swapon --show 2>/dev/null || echo " (none)" | |||
| 225 | + | echo | |||
| 226 | + | ||||
| 227 | + | echo "Partitions:" | |||
| 228 | + | lsblk 2>/dev/null | head -20 | |||
| 229 | + | } | |||
| 230 | + | ||||
| 231 | + | # ============================================================ | |||
| 232 | + | # MAIN EXECUTION | |||
| 233 | + | # ============================================================ | |||
| 234 | + | ||||
| 235 | + | case "$CLEANUP_MODE" in | |||
| 236 | + | default) | |||
| 237 | + | log_cleanup "=== ArchUp Cleanup (DEFAULT) ===" | |||
| 238 | + | cleanup_mounts | |||
| 239 | + | cleanup_encryption | |||
| 240 | + | cleanup_swap | |||
| 241 | + | cleanup_processes | |||
| 242 | + | cleanup_sync | |||
| 243 | + | log_success "=== Default cleanup complete ===" | |||
| 244 | + | ;; | |||
| 245 | + | ||||
| 246 | + | full) | |||
| 247 | + | log_cleanup "=== ArchUp Cleanup (FULL - DESTRUCTIVE) ===" | |||
| 248 | + | cleanup_mounts | |||
| 249 | + | cleanup_encryption | |||
| 250 | + | cleanup_swap | |||
| 251 | + | cleanup_processes | |||
| 252 | + | cleanup_full | |||
| 253 | + | cleanup_sync | |||
| 254 | + | log_success "=== Full cleanup complete ===" | |||
| 255 | + | ;; | |||
| 256 | + | ||||
| 257 | + | uefi-cleanup) | |||
| 258 | + | cleanup_uefi_entries | |||
| 259 | + | ;; | |||
| 260 | + | ||||
| 261 | + | diagnostic) | |||
| 262 | + | cleanup_diagnostic | |||
| 263 | + | ;; | |||
| 264 | + | ||||
| 265 | + | *) | |||
| 266 | + | echo "Usage: cleanup.sh [default|full|uefi-cleanup|diagnostic]" | |||
| 267 | + | echo "" | |||
| 268 | + | echo "Modes:" | |||
| 269 | + | echo " default - Unmount, close LUKS, disable swap (safe, always done)" | |||
| 270 | + | echo " full - Also delete /mnt content (destructive)" | |||
| 271 | + | echo " uefi-cleanup - Show UEFI boot entries (manual cleanup)" | |||
| 272 | + | echo " diagnostic - Show current system state" | |||
| 273 | + | exit 1 | |||
| 274 | + | ;; | |||
| 275 | + | esac | |||
M install/partitioning/format.sh +0 -4
| @@ -3,10 +3,6 @@ | |||
| 3 | 3 | ||
| 4 | 4 | gum style --foreground 6 --padding "1 0 0 $PADDING_LEFT" "Formatting partitions..." | |
| 5 | 5 | ||
| 6 | - | # Ensure nothing is mounted (cleanup from previous installation attempts) | |
| 7 | - | umount -R /mnt >> "$ARCHUP_INSTALL_LOG_FILE" 2>&1 || true | |
| 8 | - | swapoff -a >> "$ARCHUP_INSTALL_LOG_FILE" 2>&1 || true | |
| 9 | - | ||
| 10 | 6 | # Wipe any existing signatures on EFI partition | |
| 11 | 7 | wipefs -af "$ARCHUP_EFI_PART" >> "$ARCHUP_INSTALL_LOG_FILE" 2>&1 | |
| 12 | 8 | ||
| @@ -3,10 +3,6 @@ | |||||
| 3 | 3 | ||||
| 4 | gum style --foreground 6 --padding "1 0 0 $PADDING_LEFT" "Formatting partitions..." | 4 | gum style --foreground 6 --padding "1 0 0 $PADDING_LEFT" "Formatting partitions..." | ||
| 5 | 5 | ||||
| 6 | - | # Ensure nothing is mounted (cleanup from previous installation attempts) | |||
| 7 | - | umount -R /mnt >> "$ARCHUP_INSTALL_LOG_FILE" 2>&1 || true | |||
| 8 | - | swapoff -a >> "$ARCHUP_INSTALL_LOG_FILE" 2>&1 || true | |||
| 9 | - | ||||
| 10 | # Wipe any existing signatures on EFI partition | 6 | # Wipe any existing signatures on EFI partition | ||
| 11 | wipefs -af "$ARCHUP_EFI_PART" >> "$ARCHUP_INSTALL_LOG_FILE" 2>&1 | 7 | wipefs -af "$ARCHUP_EFI_PART" >> "$ARCHUP_INSTALL_LOG_FILE" 2>&1 | ||
| 12 | 8 | ||||