# ============================================================================ # Snapper Snapshot Functions for CachyOS/Arch # ============================================================================ # Add these functions to your ~/.zshrc or ~/.dotfiles/zsh/.zshrc # Colors for output SNAP_GREEN='\033[0;32m' SNAP_YELLOW='\033[1;33m' SNAP_RED='\033[0;31m' SNAP_BLUE='\033[0;34m' SNAP_NC='\033[0m' # No Color # ============================================================================ # Main Snapshot Function with Limine Validation # ============================================================================ snap-create() { local description="$*" local snap_config="root" local limine_conf="/boot/limine.conf" # Print header echo -e "\n${SNAP_BLUE}╔════════════════════════════════════════════════════════════╗${SNAP_NC}" echo -e "${SNAP_BLUE}║${SNAP_NC} Snapper Snapshot Creation & Validation ${SNAP_BLUE}║${SNAP_NC}" echo -e "${SNAP_BLUE}╚════════════════════════════════════════════════════════════╝${SNAP_NC}\n" # Check if description was provided if [[ -z "$description" ]]; then echo -e "${SNAP_YELLOW}⚠${SNAP_NC} No description provided" echo -n "Enter snapshot description: " read description if [[ -z "$description" ]]; then echo -e "${SNAP_RED}✗${SNAP_NC} Description required. Aborting." return 1 fi fi # Check if limine.conf exists if [[ ! -f "$limine_conf" ]]; then echo -e "${SNAP_RED}✗${SNAP_NC} Limine config not found: $limine_conf" return 1 fi # Get limine.conf state before snapshot echo -e "${SNAP_BLUE}==>${SNAP_NC} Checking limine.conf state before snapshot" local before_checksum=$(sudo md5sum "$limine_conf" | awk '{print $1}') local before_entries=$(sudo grep -c "^:.*Snapshot" "$limine_conf" || echo "0") echo -e "${SNAP_GREEN}✓${SNAP_NC} Before: $before_entries snapshot entries" echo -e "${SNAP_GREEN}✓${SNAP_NC} Before checksum: $before_checksum" # Create the snapshot echo -e "\n${SNAP_BLUE}==>${SNAP_NC} Creating snapshot: \"$description\"" local snapshot_num=$(sudo snapper -c "$snap_config" create \ --description "$description" \ --print-number) if [[ -z "$snapshot_num" ]]; then echo -e "${SNAP_RED}✗${SNAP_NC} Failed to create snapshot" return 1 fi echo -e "${SNAP_GREEN}✓${SNAP_NC} Snapshot created: #$snapshot_num" # Wait a moment for the plugin to run echo -e "\n${SNAP_BLUE}==>${SNAP_NC} Waiting for snapper-limine-plugin to update limine.conf..." sleep 2 # Get limine.conf state after snapshot echo -e "${SNAP_BLUE}==>${SNAP_NC} Validating limine.conf update" local after_checksum=$(sudo md5sum "$limine_conf" | awk '{print $1}') local after_entries=$(sudo grep -c "^:.*Snapshot" "$limine_conf" || echo "0") # Validate the update local validation_passed=true if [[ "$before_checksum" == "$after_checksum" ]]; then echo -e "${SNAP_RED}✗${SNAP_NC} limine.conf was NOT updated (checksum unchanged)" validation_passed=false else echo -e "${SNAP_GREEN}✓${SNAP_NC} limine.conf was updated" fi if [[ "$after_entries" -le "$before_entries" ]]; then echo -e "${SNAP_RED}✗${SNAP_NC} No new snapshot entry added to limine.conf" validation_passed=false else local new_entries=$((after_entries - before_entries)) echo -e "${SNAP_GREEN}✓${SNAP_NC} Added $new_entries new snapshot entry/entries" fi # Check for the specific snapshot in limine.conf echo -e "\n${SNAP_BLUE}==>${SNAP_NC} Searching for snapshot #$snapshot_num in limine.conf" if sudo grep -q "Snapshot $snapshot_num" "$limine_conf"; then echo -e "${SNAP_GREEN}✓${SNAP_NC} Found snapshot #$snapshot_num in limine.conf" # Show the entry echo -e "\n${SNAP_BLUE}Snapshot entry:${SNAP_NC}" sudo grep -A 3 "Snapshot $snapshot_num" "$limine_conf" | sed 's/^/ /' else echo -e "${SNAP_RED}✗${SNAP_NC} Snapshot #$snapshot_num NOT found in limine.conf" validation_passed=false fi # Print summary echo -e "\n${SNAP_BLUE}╔════════════════════════════════════════════════════════════╗${SNAP_NC}" echo -e "${SNAP_BLUE}║${SNAP_NC} Summary ${SNAP_BLUE}║${SNAP_NC}" echo -e "${SNAP_BLUE}╚════════════════════════════════════════════════════════════╝${SNAP_NC}" echo -e "Snapshot Number: #$snapshot_num" echo -e "Description: \"$description\"" echo -e "Config: $snap_config" echo -e "Before entries: $before_entries" echo -e "After entries: $after_entries" if [[ "$validation_passed" == true ]]; then echo -e "Status: ${SNAP_GREEN}✓ VALIDATED${SNAP_NC}" echo -e "\n${SNAP_GREEN}✓${SNAP_NC} Snapshot created and limine.conf successfully updated!" return 0 else echo -e "Status: ${SNAP_RED}✗ VALIDATION FAILED${SNAP_NC}" echo -e "\n${SNAP_RED}✗${SNAP_NC} Snapshot created but limine.conf validation failed!" echo -e "${SNAP_YELLOW}⚠${SNAP_NC} Check if snapper-limine-plugin is installed and configured" return 1 fi } # ============================================================================ # Helper Functions # ============================================================================ # List recent snapshots snap-list() { local count="${1:-10}" echo -e "${SNAP_BLUE}Recent $count snapshots:${SNAP_NC}\n" sudo snapper -c root list | tail -n "$((count + 1))" } # Show snapshot details snap-show() { if [[ -z "$1" ]]; then echo -e "${SNAP_RED}✗${SNAP_NC} Usage: snap-show " return 1 fi echo -e "${SNAP_BLUE}Snapshot #$1 details:${SNAP_NC}\n" sudo snapper -c root list | grep "^\s*$1\s" echo -e "\n${SNAP_BLUE}In limine.conf:${SNAP_NC}" if sudo grep -q "Snapshot $1" /boot/limine.conf; then sudo grep -A 3 "Snapshot $1" /boot/limine.conf else echo -e "${SNAP_YELLOW}⚠${SNAP_NC} Not found in limine.conf" fi } # Delete snapshot with limine validation snap-delete() { if [[ -z "$1" ]]; then echo -e "${SNAP_RED}✗${SNAP_NC} Usage: snap-delete " return 1 fi local snapshot_num="$1" local limine_conf="/boot/limine.conf" echo -e "${SNAP_BLUE}==>${SNAP_NC} Deleting snapshot #$snapshot_num" # Check before deletion local before_entries=$(sudo grep -c "^:.*Snapshot" "$limine_conf" || echo "0") # Delete the snapshot sudo snapper -c root delete "$snapshot_num" if [[ $? -eq 0 ]]; then echo -e "${SNAP_GREEN}✓${SNAP_NC} Snapshot #$snapshot_num deleted" # Wait for plugin to update sleep 2 # Check after deletion local after_entries=$(sudo grep -c "^:.*Snapshot" "$limine_conf" || echo "0") if [[ "$after_entries" -lt "$before_entries" ]]; then echo -e "${SNAP_GREEN}✓${SNAP_NC} limine.conf updated (removed entry)" else echo -e "${SNAP_YELLOW}⚠${SNAP_NC} limine.conf may not have been updated" fi # Verify snapshot is gone from limine.conf if ! sudo grep -q "Snapshot $snapshot_num" "$limine_conf"; then echo -e "${SNAP_GREEN}✓${SNAP_NC} Snapshot #$snapshot_num removed from limine.conf" else echo -e "${SNAP_RED}✗${SNAP_NC} Snapshot #$snapshot_num still in limine.conf!" fi else echo -e "${SNAP_RED}✗${SNAP_NC} Failed to delete snapshot #$snapshot_num" return 1 fi } # Check limine.conf for all snapshots snap-check-limine() { local limine_conf="/boot/limine.conf" echo -e "${SNAP_BLUE}╔════════════════════════════════════════════════════════════╗${SNAP_NC}" echo -e "${SNAP_BLUE}║${SNAP_NC} Limine Snapshot Entries ${SNAP_BLUE}║${SNAP_NC}" echo -e "${SNAP_BLUE}╚════════════════════════════════════════════════════════════╝${SNAP_NC}\n" if [[ ! -f "$limine_conf" ]]; then echo -e "${SNAP_RED}✗${SNAP_NC} Limine config not found: $limine_conf" return 1 fi # Count snapshot entries local entry_count=$(sudo grep -c "^:.*Snapshot" "$limine_conf" || echo "0") echo -e "${SNAP_BLUE}Total snapshot entries:${SNAP_NC} $entry_count\n" # Show all snapshot entries if [[ "$entry_count" -gt 0 ]]; then echo -e "${SNAP_BLUE}Snapshot boot entries:${SNAP_NC}\n" sudo grep "^:.*Snapshot" "$limine_conf" | nl -w2 -s'. ' else echo -e "${SNAP_YELLOW}⚠${SNAP_NC} No snapshot entries found in limine.conf" fi # Compare with actual snapshots echo -e "\n${SNAP_BLUE}Comparing with snapper list:${SNAP_NC}\n" local snapper_count=$(sudo snapper -c root list | grep -v "single" | tail -n +3 | wc -l) echo -e "Snapshots in snapper: $snapper_count" echo -e "Entries in limine.conf: $entry_count" if [[ "$snapper_count" -eq "$entry_count" ]]; then echo -e "Status: ${SNAP_GREEN}✓ SYNCED${SNAP_NC}" else echo -e "Status: ${SNAP_YELLOW}⚠ OUT OF SYNC${SNAP_NC}" echo -e "\n${SNAP_YELLOW}Note:${SNAP_NC} Some snapshots may be excluded from boot menu by configuration" fi } # Validate snapper-limine-plugin is working snap-validate-plugin() { echo -e "${SNAP_BLUE}╔════════════════════════════════════════════════════════════╗${SNAP_NC}" echo -e "${SNAP_BLUE}║${SNAP_NC} Snapper-Limine-Plugin Validation ${SNAP_BLUE}║${SNAP_NC}" echo -e "${SNAP_BLUE}╚════════════════════════════════════════════════════════════╝${SNAP_NC}\n" # Check if plugin is installed echo -e "${SNAP_BLUE}==>${SNAP_NC} Checking plugin installation" if pacman -Qi snapper-limine-plugin &>/dev/null; then echo -e "${SNAP_GREEN}✓${SNAP_NC} snapper-limine-plugin is installed" pacman -Qi snapper-limine-plugin | grep "Version" | sed 's/^/ /' else echo -e "${SNAP_RED}✗${SNAP_NC} snapper-limine-plugin is NOT installed" echo -e "\n${SNAP_YELLOW}Install with:${SNAP_NC} paru -S snapper-limine-plugin" return 1 fi # Check plugin script location echo -e "\n${SNAP_BLUE}==>${SNAP_NC} Checking plugin script" local plugin_script="/usr/share/limine/snapper-limine.sh" if [[ -f "$plugin_script" ]]; then echo -e "${SNAP_GREEN}✓${SNAP_NC} Plugin script exists: $plugin_script" ls -lh "$plugin_script" | sed 's/^/ /' else echo -e "${SNAP_RED}✗${SNAP_NC} Plugin script not found: $plugin_script" fi # Check snapper config echo -e "\n${SNAP_BLUE}==>${SNAP_NC} Checking snapper configuration" if [[ -f "/etc/snapper/configs/root" ]]; then echo -e "${SNAP_GREEN}✓${SNAP_NC} Snapper root config exists" else echo -e "${SNAP_RED}✗${SNAP_NC} Snapper root config not found" fi # Check limine.conf echo -e "\n${SNAP_BLUE}==>${SNAP_NC} Checking limine.conf" if [[ -f "/boot/limine.conf" ]]; then echo -e "${SNAP_GREEN}✓${SNAP_NC} limine.conf exists" local snap_entries=$(sudo grep -c "^:.*Snapshot" /boot/limine.conf || echo "0") echo -e " Snapshot entries: $snap_entries" else echo -e "${SNAP_RED}✗${SNAP_NC} limine.conf not found" fi echo -e "\n${SNAP_GREEN}✓${SNAP_NC} Validation complete" } # Quick snapshot aliases alias snap='snap-create' alias snapls='snap-list' alias snaprm='snap-delete' alias snapshow='snap-show' alias snapcheck='snap-check-limine' # ============================================================================ # Usage Examples (commented out - uncomment to see examples) # ============================================================================ # snap-create "Before system update" # snap-list 20 # snap-show 42 # snap-delete 42 # snap-check-limine # snap-validate-plugin