cleanup script changes and things i dont rmeember :(

This commit is contained in:
cnst
2024-09-14 21:23:59 +02:00
parent 79c5d20d61
commit e75e115483
8 changed files with 345 additions and 247 deletions

View File

@@ -1,11 +1,18 @@
#!/bin/bash
# Script to clean up old initrd and kernel files in /boot/EFI/nixos
# Make sure it's added to flake.nix, then run:
# "nix build .#packages.x86_64-linux.cleanup-boot".
#
# Build the script with:
# nix build .#packages.x86_64-linux.cleanup-boot
# Run the script with:
# nix run .#cleanup-boot -- --dry-run
# The '--' is required to pass arguments to the script.
#
# This script keeps the latest N kernel/initrd pairs (entries).
# Each entry consists of a kernel and an initrd file identified by the same version number.
# Number of generations to keep
KEEP_GENERATIONS=4
# Default number of entries to keep
KEEP_ENTRIES=4
# Log file for cleanup actions
LOG_FILE="/var/log/cleanup-boot.log"
@@ -13,77 +20,212 @@ LOG_FILE="/var/log/cleanup-boot.log"
# Dry run flag
DRY_RUN=false
# Check for dry run argument
if [ "$1" = "--dry-run" ]; then
DRY_RUN=true
fi
# Include incomplete entries flag
INCLUDE_INCOMPLETE=false
# Function to log messages
log() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
# Function to display usage information
usage() {
echo "Usage: $0 [--dry-run] [--keep N] [--include-incomplete] [--help]"
echo
echo "Note: When running with 'nix run', use '--' before script arguments."
echo
echo "Options:"
echo " --dry-run Perform a trial run with no changes made."
echo " --keep N Keep the latest N kernel/initrd pairs (default: 4)."
echo " --include-incomplete Include incomplete entries in deletion."
echo " --help, -h Show this help message."
echo
echo "Examples:"
echo " nix run .#cleanup-boot -- --dry-run"
echo " ./result --keep 5"
exit 1
}
# Exit on any error
set -e
# Parse command-line arguments
while [[ "$#" -gt 0 ]]; do
case "$1" in
--dry-run)
DRY_RUN=true
;;
--keep)
if [[ -n "${2:-}" && "$2" =~ ^[0-9]+$ ]]; then
KEEP_ENTRIES="$2"
shift
else
echo "Error: --keep requires a numeric argument."
usage
fi
;;
--include-incomplete)
INCLUDE_INCOMPLETE=true
;;
--help | -h)
usage
;;
*)
echo "Unknown option: $1"
usage
;;
esac
shift
done
log "Starting cleanup script. Keeping the latest $KEEP_GENERATIONS generations."
# Exit on any error, undefined variable, or pipeline failure
set -euo pipefail
# List the initrd files in /boot/EFI/nixos sorted by modification time (oldest first)
mapfile -t initrd_files < <(find /boot/EFI/nixos -type f -name '*initrd*.efi' -printf '%T@ %p\n' | sort -n)
# List the kernel files in /boot/EFI/nixos sorted by modification time (oldest first)
mapfile -t kernel_files < <(find /boot/EFI/nixos -type f -name '*kernel*.efi' -printf '%T@ %p\n' | sort -n)
# Count the number of initrd and kernel files
initrd_count=${#initrd_files[@]}
kernel_count=${#kernel_files[@]}
log "Found $initrd_count initrd files and $kernel_count kernel files."
# Initialize arrays to hold files to delete
delete_initrd_files=()
delete_kernel_files=()
# If there are fewer than KEEP_GENERATIONS initrd files, don't delete any
if [ "$initrd_count" -le "$KEEP_GENERATIONS" ]; then
log "Fewer than $KEEP_GENERATIONS initrd files found. No initrd files will be deleted."
else
# Get the initrd files to delete
delete_initrd_files=("${initrd_files[@]:0:initrd_count-KEEP_GENERATIONS}")
# Check for root privileges
if [ "$EUID" -ne 0 ]; then
echo "Error: Please run as root."
exit 1
fi
# If there are fewer than KEEP_GENERATIONS kernel files, don't delete any
if [ "$kernel_count" -le "$KEEP_GENERATIONS" ]; then
log "Fewer than $KEEP_GENERATIONS kernel files found. No kernel files will be deleted."
else
# Get the kernel files to delete
delete_kernel_files=("${kernel_files[@]:0:kernel_count-KEEP_GENERATIONS}")
# Check if log file is writable
if ! touch "$LOG_FILE" &>/dev/null; then
echo "Error: Cannot write to log file $LOG_FILE"
exit 1
fi
# Function to log messages with timestamps
log() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
}
log "Starting cleanup script. Keeping the latest $KEEP_ENTRIES kernel/initrd pairs."
# Collect all .efi files in /boot/EFI/nixos
mapfile -t efi_files < <(find /boot/EFI/nixos -type f -name '*.efi')
declare -A entries
# Parse filenames to group kernel and initrd files by their version number
for file in "${efi_files[@]}"; do
basename=$(basename "$file")
# Extract the version number
if [[ "$basename" =~ ^(initrd|kernel)-(.*)-(.*)\.efi$ ]]; then
type="${BASH_REMATCH[1]}"
version="${BASH_REMATCH[2]}"
# hash="${BASH_REMATCH[3]}" # Removed unused variable
elif [[ "$basename" =~ ^(.*)-(.*)-(initrd|kernel)\.efi$ ]]; then
# hash="${BASH_REMATCH[1]}" # Removed unused variable
version="${BASH_REMATCH[2]}"
type="${BASH_REMATCH[3]}"
else
log "Warning: Unrecognized filename format: $basename"
continue
fi
key="$version"
entries["$key,$type"]="$file"
# Store the earliest modification time among kernel and initrd
file_mtime=$(stat -c '%Y' "$file")
existing_mtime="${entries["$key,mtime"]:-}"
if [[ -z "$existing_mtime" ]] || [[ "$file_mtime" -lt "$existing_mtime" ]]; then
entries["$key,mtime"]="$file_mtime"
fi
done
# Decide whether to include incomplete entries
declare -A valid_entries
if [ "$INCLUDE_INCOMPLETE" = true ]; then
# Include all entries
for key in "${!entries[@]}"; do
if [[ "$key" =~ ,mtime$ ]]; then
version="${key%,mtime}"
valid_entries["$version,initrd"]="${entries["$version,initrd"]:-}"
valid_entries["$version,kernel"]="${entries["$version,kernel"]:-}"
valid_entries["$version,mtime"]="${entries["$version,mtime"]}"
fi
done
else
# Include only complete entries
for key in "${!entries[@]}"; do
if [[ "$key" =~ ,mtime$ ]]; then
version="${key%,mtime}"
if [[ -n "${entries["$version,initrd"]:-}" && -n "${entries["$version,kernel"]:-}" ]]; then
valid_entries["$version,initrd"]="${entries["$version,initrd"]}"
valid_entries["$version,kernel"]="${entries["$version,kernel"]}"
valid_entries["$version,mtime"]="${entries["$version,mtime"]}"
else
log "Warning: Incomplete entry detected for version $version."
fi
fi
done
fi
# Sort the entries by modification time (newest first)
mapfile -t sorted_entries < <(
for key in "${!valid_entries[@]}"; do
if [[ "$key" =~ ,mtime$ ]]; then
version="${key%,mtime}"
mtime="${valid_entries[$key]}"
echo "$mtime:$version"
fi
done | sort -rn | awk -F: '{print $2}'
)
# Remove duplicates
unique_versions=()
declare -A seen_versions
for version in "${sorted_entries[@]}"; do
if [[ -z "${seen_versions[$version]:-}" ]]; then
unique_versions+=("$version")
seen_versions["$version"]=1
fi
done
entry_count=${#unique_versions[@]}
log "Found $entry_count kernel/initrd pairs."
if [ "$entry_count" -le "$KEEP_ENTRIES" ]; then
log "Fewer than or equal to $KEEP_ENTRIES pairs found. No files will be deleted."
exit 0
fi
# Determine entries to delete
entries_to_delete=("${unique_versions[@]:$KEEP_ENTRIES}")
# Log the files identified for deletion
log "Files identified for deletion:"
for file_entry in "${delete_initrd_files[@]}" "${delete_kernel_files[@]}"; do
file=$(echo "$file_entry" | cut -d' ' -f2-)
log "$file"
delete_files=()
for version in "${entries_to_delete[@]}"; do
initrd_file="${valid_entries["$version,initrd"]:-}"
kernel_file="${valid_entries["$version,kernel"]:-}"
if [ -n "$initrd_file" ]; then
delete_files+=("$initrd_file")
log "$initrd_file"
fi
if [ -n "$kernel_file" ]; then
delete_files+=("$kernel_file")
log "$kernel_file"
fi
done
# Confirm dry run mode
if [ "$DRY_RUN" = true ]; then
log "Dry run mode enabled. No files will be deleted."
log "Dry run mode enabled. No files will be deleted."
fi
# Remove old files
for file_entry in "${delete_initrd_files[@]}" "${delete_kernel_files[@]}"; do
file=$(echo "$file_entry" | cut -d' ' -f2-)
if [ "$DRY_RUN" = false ]; then
if rm -f "$file"; then
log "Deleted: $file"
else
log "Failed to delete: $file"
fi
else
log "Dry run - would delete: $file"
fi
for file in "${delete_files[@]}"; do
# Security check: Ensure the file is within /boot/EFI/nixos
if [[ "$file" != /boot/EFI/nixos/* ]]; then
log "Warning: Attempted to delete file outside of /boot/EFI/nixos: $file"
continue
fi
if [ "$DRY_RUN" = false ]; then
if rm -f "$file"; then
log "Deleted: $file"
else
log "Failed to delete: $file"
fi
else
log "Dry run - would delete: $file"
fi
done
log "Cleanup script completed."