189 lines
4.5 KiB
Bash
189 lines
4.5 KiB
Bash
#!/bin/sh
|
||
# System configuration backup script
|
||
# Backs up /etc and dotfiles (lightweight backup)
|
||
|
||
set -e
|
||
|
||
# Config
|
||
CONFIG_FILE="/etc/backup.conf"
|
||
LOG_DIR="${HOME}/.local/var/log"
|
||
LOG_FILE="${LOG_DIR}/backup.log"
|
||
LOCK_FILE="/tmp/backup-configs.lock"
|
||
|
||
# Ensure log directory exists
|
||
mkdir -p "$LOG_DIR"
|
||
|
||
# Colors
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
BLUE='\033[0;34m'
|
||
NC='\033[0m'
|
||
|
||
log() {
|
||
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" >> "$LOG_FILE"
|
||
echo "$*"
|
||
}
|
||
|
||
error() {
|
||
printf "${RED}✖${NC} %s\n" "$1"
|
||
log "ERROR: $1"
|
||
}
|
||
|
||
info() {
|
||
printf "${BLUE}ℹ${NC} %s\n" "$1"
|
||
log "INFO: $1"
|
||
}
|
||
|
||
success() {
|
||
printf "${GREEN}✓${NC} %s\n" "$1"
|
||
log "SUCCESS: $1"
|
||
}
|
||
|
||
# Load config
|
||
if [ ! -f "$CONFIG_FILE" ]; then
|
||
error "Configuration file not found: $CONFIG_FILE"
|
||
exit 1
|
||
fi
|
||
|
||
# shellcheck source=/dev/null
|
||
. "$CONFIG_FILE"
|
||
|
||
# Create lock file
|
||
if [ -f "$LOCK_FILE" ]; then
|
||
error "Config backup already running"
|
||
exit 1
|
||
fi
|
||
|
||
trap 'rm -f "$LOCK_FILE"' EXIT
|
||
touch "$LOCK_FILE"
|
||
|
||
# Start backup
|
||
log "=========================================="
|
||
log "Starting CONFIGURATION BACKUP"
|
||
log "=========================================="
|
||
|
||
# Check NAS connectivity
|
||
info "Checking NAS connectivity..."
|
||
if ! ssh -p "$NAS_PORT" -o ConnectTimeout=5 -o BatchMode=yes \
|
||
"${NAS_USER}@${NAS_HOST}" "echo test" >/dev/null 2>&1; then
|
||
error "SSH connection to NAS failed"
|
||
exit 1
|
||
fi
|
||
|
||
success "NAS is reachable"
|
||
|
||
# Create backup directory name with timestamp
|
||
BACKUP_NAME="config-$(date +%Y%m%d-%H%M%S)"
|
||
BACKUP_DEST="${NAS_USER}@${NAS_HOST}:${NAS_PATH}/${BACKUP_NAME}"
|
||
|
||
info "Backup destination: ${BACKUP_DEST}"
|
||
|
||
# Create temporary directory for staging
|
||
TEMP_DIR=$(mktemp -d)
|
||
trap 'rm -rf "$TEMP_DIR" 2>/dev/null; rm -f "$LOCK_FILE"' EXIT
|
||
|
||
CONFIG_STAGE="$TEMP_DIR/configs"
|
||
mkdir -p "$CONFIG_STAGE"
|
||
|
||
# Copy /etc (excluding large/unnecessary files)
|
||
info "Copying system configs from /etc..."
|
||
rsync -a --delete \
|
||
--exclude='ssl/certs' \
|
||
--exclude='ca-certificates' \
|
||
/etc/ "$CONFIG_STAGE/etc/" 2>/dev/null || true
|
||
|
||
# Copy important dotfiles from home
|
||
info "Copying dotfiles..."
|
||
mkdir -p "$CONFIG_STAGE/home"
|
||
|
||
# Copy select dotfiles and configs
|
||
for item in \
|
||
.zshrc .bashrc .gitconfig .gitmux.conf \
|
||
.config/nvim \
|
||
.config/hypr \
|
||
.config/waybar \
|
||
.config/tmux \
|
||
.config/bat \
|
||
.config/starship.toml \
|
||
.config/ghostty \
|
||
.config/alxndrhi \
|
||
.local/share/chezmoi; do
|
||
|
||
if [ -e "/home/alexander/$item" ]; then
|
||
mkdir -p "$(dirname "$CONFIG_STAGE/home/$item")"
|
||
cp -r "/home/alexander/$item" "$CONFIG_STAGE/home/$item" 2>/dev/null || true
|
||
fi
|
||
done
|
||
|
||
# Copy portage config
|
||
info "Copying Portage configuration..."
|
||
if [ -d /etc/portage ]; then
|
||
mkdir -p "$CONFIG_STAGE/portage"
|
||
cp -r /etc/portage/* "$CONFIG_STAGE/portage/" 2>/dev/null || true
|
||
fi
|
||
|
||
# Copy system scripts
|
||
info "Copying custom scripts..."
|
||
if [ -d /usr/local/bin ]; then
|
||
mkdir -p "$CONFIG_STAGE/scripts"
|
||
cp -r /usr/local/bin/* "$CONFIG_STAGE/scripts/" 2>/dev/null || true
|
||
fi
|
||
|
||
# Create a manifest file
|
||
info "Creating backup manifest..."
|
||
cat > "$CONFIG_STAGE/MANIFEST.txt" <<EOF
|
||
Configuration Backup
|
||
Created: $(date)
|
||
Hostname: $(hostname)
|
||
Kernel: $(uname -r)
|
||
|
||
Contents:
|
||
- /etc (system configuration)
|
||
- Dotfiles from /home/alexander
|
||
- Portage configuration (/etc/portage)
|
||
- Custom scripts (/usr/local/bin)
|
||
|
||
To restore:
|
||
rsync -av etc/ /etc/
|
||
rsync -av home/ /home/alexander/
|
||
rsync -av portage/ /etc/portage/
|
||
rsync -av scripts/ /usr/local/bin/
|
||
EOF
|
||
|
||
# Run rsync backup to NAS
|
||
info "Uploading to NAS..."
|
||
|
||
if rsync -avz --delete \
|
||
--rsync-path="mkdir -p ${NAS_PATH}/${BACKUP_NAME} && rsync" \
|
||
-e "ssh -p ${NAS_PORT}" \
|
||
"$CONFIG_STAGE/" \
|
||
"$BACKUP_DEST" >> "$LOG_FILE" 2>&1; then
|
||
|
||
success "Backup completed successfully!"
|
||
|
||
# Update last backup timestamp
|
||
LAST_BACKUP_FILE="${HOME}/.local/var/backup/last-backup"
|
||
mkdir -p "$(dirname "$LAST_BACKUP_FILE")"
|
||
date +%s > "$LAST_BACKUP_FILE"
|
||
|
||
# Log backup size
|
||
BACKUP_SIZE=$(ssh -p "$NAS_PORT" "${NAS_USER}@${NAS_HOST}" \
|
||
"du -sh '${NAS_PATH}/${BACKUP_NAME}' 2>/dev/null | cut -f1" || echo "unknown")
|
||
info "Backup size: $BACKUP_SIZE"
|
||
|
||
# Clean up old backups
|
||
info "Cleaning up old backups (keeping last ${RETENTION_COUNT})..."
|
||
ssh -p "$NAS_PORT" "${NAS_USER}@${NAS_HOST}" \
|
||
"cd '${NAS_PATH}' && ls -t | grep '^config-' | tail -n +$((RETENTION_COUNT + 1)) | xargs -r rm -rf" \
|
||
>> "$LOG_FILE" 2>&1 || true
|
||
|
||
else
|
||
error "Backup failed! Check $LOG_FILE for details"
|
||
exit 1
|
||
fi
|
||
|
||
log "=========================================="
|
||
log "Backup completed at $(date)"
|
||
log "=========================================="
|