394 lines
13 KiB
Bash
Executable File
394 lines
13 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# restore-rocknix.sh - Restore script for ROCKNIX configurations
|
|
#
|
|
# Usage:
|
|
# ./restore-rocknix.sh [OPTIONS]
|
|
#
|
|
# Options:
|
|
# --host HOST Target console host
|
|
# --user USER SSH user (default: root)
|
|
# --backup FILE .tar.gz backup file to restore
|
|
# --all Restore all components without prompting
|
|
# --help Show help
|
|
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
source "$SCRIPT_DIR/lib-common.sh"
|
|
|
|
# Default values
|
|
BACKUP_FILE=""
|
|
RESTORE_ALL=false
|
|
|
|
# Parse arguments
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--host)
|
|
ROCKNIX_HOST="$2"
|
|
shift 2
|
|
;;
|
|
--user)
|
|
ROCKNIX_USER="$2"
|
|
shift 2
|
|
;;
|
|
--password)
|
|
ROCKNIX_PASSWORD="$2"
|
|
shift 2
|
|
;;
|
|
--backup)
|
|
BACKUP_FILE="$2"
|
|
shift 2
|
|
;;
|
|
--all)
|
|
RESTORE_ALL=true
|
|
shift
|
|
;;
|
|
--help)
|
|
echo "Usage: $0 [OPTIONS]"
|
|
echo ""
|
|
echo "Options:"
|
|
echo " --host HOST Target console host"
|
|
echo " --user USER SSH user (default: $ROCKNIX_USER)"
|
|
echo " --password PASS SSH password"
|
|
echo " --backup FILE .tar.gz backup file to restore"
|
|
echo " --all Restore all components"
|
|
echo " --help Show this help"
|
|
exit 0
|
|
;;
|
|
*)
|
|
log ERROR "Unknown option: $1"
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
# Check dependencies
|
|
check_deps || exit 1
|
|
|
|
# Ask for password if not configured
|
|
ask_password || exit 1
|
|
|
|
# If no backup specified, list available ones
|
|
if [[ -z "$BACKUP_FILE" ]]; then
|
|
log INFO "Searching for backups in ${BACKUP_DIR}..."
|
|
|
|
if [[ ! -d "$BACKUP_DIR" ]]; then
|
|
log ERROR "Backup directory not found: $BACKUP_DIR"
|
|
log INFO "Run first: ./backup-rocknix.sh"
|
|
exit 1
|
|
fi
|
|
|
|
BACKUPS=($(find "$BACKUP_DIR" -name "rocknix-config-*.tar.gz" -type f | sort -r))
|
|
|
|
if [[ ${#BACKUPS[@]} -eq 0 ]]; then
|
|
log ERROR "No backups found in ${BACKUP_DIR}"
|
|
log INFO "Run first: ./backup-rocknix.sh"
|
|
exit 1
|
|
fi
|
|
|
|
echo ""
|
|
echo -e "${CYAN}Available backups:${NC}"
|
|
echo ""
|
|
|
|
for i in "${!BACKUPS[@]}"; do
|
|
local backup="${BACKUPS[$i]}"
|
|
local name=$(basename "$backup")
|
|
local size=$(du -h "$backup" | cut -f1)
|
|
local date=$(stat -c %y "$backup" 2>/dev/null | cut -d'.' -f1)
|
|
|
|
echo -e " ${GREEN}$((i+1))${NC}) ${name}"
|
|
echo -e " Size: ${size} | Date: ${date}"
|
|
done
|
|
|
|
echo ""
|
|
read -p "Select backup (1-${#BACKUPS[@]}): " choice
|
|
|
|
if [[ "$choice" -lt 1 || "$choice" -gt ${#BACKUPS[@]} ]]; then
|
|
log ERROR "Invalid selection"
|
|
exit 1
|
|
fi
|
|
|
|
BACKUP_FILE="${BACKUPS[$((choice-1))]}"
|
|
fi
|
|
|
|
# Verify backup file exists
|
|
if [[ ! -f "$BACKUP_FILE" ]]; then
|
|
log ERROR "Backup file not found: $BACKUP_FILE"
|
|
exit 1
|
|
fi
|
|
|
|
# Show backup contents
|
|
show_backup_contents "$BACKUP_FILE"
|
|
|
|
# Verify connection with target console
|
|
echo ""
|
|
ssh_check "$ROCKNIX_HOST" "$ROCKNIX_USER" || exit 1
|
|
|
|
# Detect target device
|
|
DEVICE=$(detect_device "$ROCKNIX_HOST" "$ROCKNIX_USER" 2>/dev/null || echo "unknown")
|
|
log INFO "Target device: ${DEVICE}"
|
|
|
|
# Check backup type
|
|
BACKUP_NAME=$(basename "$BACKUP_FILE")
|
|
if [[ "$BACKUP_NAME" == *"generic"* ]]; then
|
|
log WARN "This is a GENERIC backup (without device-specific settings)"
|
|
log WARN "Make sure the target device is compatible"
|
|
echo ""
|
|
read -p "Continue? (y/N): " confirm
|
|
if [[ "$confirm" != "s" && "$confirm" != "S" ]]; then
|
|
log INFO "Restore cancelled"
|
|
exit 0
|
|
fi
|
|
fi
|
|
|
|
# Create temporary directory
|
|
TMP_DIR=$(create_tmp_dir "rocknix-restore")
|
|
trap 'cleanup_tmp "$TMP_DIR"' EXIT
|
|
|
|
# Extract backup
|
|
log INFO "Extracting backup..."
|
|
tar -xzf "$BACKUP_FILE" -C "$TMP_DIR"
|
|
|
|
# Select components to restore
|
|
if [[ "$RESTORE_ALL" == "false" ]]; then
|
|
echo ""
|
|
echo -e "${CYAN}Which components do you want to restore?${NC}"
|
|
echo ""
|
|
|
|
COMPONENTS=(
|
|
"retroarch-core-options:RetroArch core-options"
|
|
"retroarch-opt:RetroArch .opt (core options)"
|
|
"retroarch-rmp:RetroArch .rmp (remaps)"
|
|
"retroarch-config:RetroArch overrides (config/)"
|
|
"shaders:Shaders"
|
|
"ppsspp:PPSSPP"
|
|
"drastic:DraStic"
|
|
"other-emu:Other emulators"
|
|
)
|
|
|
|
SELECTION=()
|
|
|
|
for i in "${!COMPONENTS[@]}"; do
|
|
IFS=':' read -r key label <<< "${COMPONENTS[$i]}"
|
|
|
|
# Determine if there are files of this type
|
|
case "$key" in
|
|
retroarch-core-options)
|
|
[[ -f "${TMP_DIR}/.config/retroarch/retroarch-core-options.cfg" ]] && available=true || available=false
|
|
;;
|
|
retroarch-opt)
|
|
find "${TMP_DIR}/.config/retroarch/" -maxdepth 1 -name "*.opt" -type f 2>/dev/null | grep -q . && available=true || available=false
|
|
;;
|
|
retroarch-rmp)
|
|
find "${TMP_DIR}/.config/retroarch/" -maxdepth 1 -name "*.rmp" -type f 2>/dev/null | grep -q . && available=true || available=false
|
|
;;
|
|
retroarch-config)
|
|
[[ -d "${TMP_DIR}/.config/retroarch/config/" ]] && available=true || available=false
|
|
;;
|
|
shaders)
|
|
[[ -d "${TMP_DIR}/shaders/" ]] && available=true || available=false
|
|
;;
|
|
ppsspp)
|
|
[[ -f "${TMP_DIR}/.config/ppsspp/PSP/SYSTEM/ppsspp.ini" ]] && available=true || available=false
|
|
;;
|
|
drastic)
|
|
[[ -d "${TMP_DIR}/.config/drastic/config/" ]] && available=true || available=false
|
|
;;
|
|
other-emu)
|
|
[[ -d "${TMP_DIR}/.config/game/" ]] || \
|
|
[[ -d "${TMP_DIR}/.config/flycast/" ]] || \
|
|
[[ -f "${TMP_DIR}/.config/duckstation/settings.ini" ]] || \
|
|
[[ -f "${TMP_DIR}/.config/yabasanshiro/.config" ]] && available=true || available=false
|
|
;;
|
|
esac
|
|
|
|
if [[ "$available" == "true" ]]; then
|
|
SELECTION+=("$key" "$label" "on")
|
|
else
|
|
SELECTION+=("$key" "$label" "off")
|
|
fi
|
|
done
|
|
|
|
CHOICES=$(dialog --checklist "Components to restore:" \
|
|
20 60 12 \
|
|
"${SELECTION[@]}" \
|
|
3>&1 1>&2 2>&3)
|
|
|
|
# If user cancels
|
|
if [[ $? -ne 0 ]]; then
|
|
log INFO "Restore cancelled"
|
|
exit 0
|
|
fi
|
|
else
|
|
# Restore all
|
|
CHOICES="retroarch-core-options retroarch-opt retroarch-rmp retroarch-config shaders ppsspp drastic other-emu"
|
|
fi
|
|
|
|
# Confirm restore
|
|
echo ""
|
|
echo -e "${YELLOW}Restore the following components on ${ROCKNIX_HOST}?${NC}"
|
|
for choice in $CHOICES; do
|
|
case "$choice" in
|
|
retroarch-core-options) echo " - RetroArch core-options" ;;
|
|
retroarch-opt) echo " - RetroArch .opt" ;;
|
|
retroarch-rmp) echo " - RetroArch .rmp" ;;
|
|
retroarch-config) echo " - RetroArch overrides" ;;
|
|
shaders) echo " - Shaders" ;;
|
|
ppsspp) echo " - PPSSPP" ;;
|
|
drastic) echo " - DraStic" ;;
|
|
other-emu) echo " - Other emulators" ;;
|
|
esac
|
|
done
|
|
|
|
echo ""
|
|
read -p "Confirm restore? (y/N): " confirm
|
|
if [[ "$confirm" != "s" && "$confirm" != "S" ]]; then
|
|
log INFO "Restore cancelled"
|
|
exit 0
|
|
fi
|
|
|
|
# Create safety backup on target console
|
|
log INFO "Creating safety backup on console..."
|
|
SAFETY_DIR="${TMP_DIR}/safety"
|
|
mkdir -p "$SAFETY_DIR"
|
|
|
|
# Download current files before overwriting
|
|
for choice in $CHOICES; do
|
|
case "$choice" in
|
|
retroarch-core-options)
|
|
download_file ".config/retroarch/retroarch-core-options.cfg" \
|
|
"${SAFETY_DIR}/retroarch-core-options.cfg" \
|
|
"$ROCKNIX_HOST" "$ROCKNIX_USER" 2>/dev/null || true
|
|
;;
|
|
# Add others if needed
|
|
esac
|
|
done
|
|
|
|
log INFO "Safety backup created"
|
|
|
|
# Restore files
|
|
log INFO "Restoring files..."
|
|
RESTORED=0
|
|
FAILED=0
|
|
|
|
for choice in $CHOICES; do
|
|
log INFO "Restoring: ${choice}..."
|
|
|
|
case "$choice" in
|
|
retroarch-core-options)
|
|
if [[ -f "${TMP_DIR}/.config/retroarch/retroarch-core-options.cfg" ]]; then
|
|
if upload_file "${TMP_DIR}/.config/retroarch/retroarch-core-options.cfg" \
|
|
".config/retroarch/retroarch-core-options.cfg" \
|
|
"$ROCKNIX_HOST" "$ROCKNIX_USER" &>/dev/null; then
|
|
RESTORED=$((RESTORED + 1))
|
|
else
|
|
FAILED=$((FAILED + 1))
|
|
log WARN "Error restoring retroarch-core-options.cfg"
|
|
fi
|
|
fi
|
|
;;
|
|
retroarch-opt)
|
|
for opt_file in "${TMP_DIR}/.config/retroarch/"*.opt; do
|
|
if [[ -f "$opt_file" ]]; then
|
|
filename=$(basename "$opt_file")
|
|
if upload_file "$opt_file" \
|
|
".config/retroarch/${filename}" \
|
|
"$ROCKNIX_HOST" "$ROCKNIX_USER" &>/dev/null; then
|
|
RESTORED=$((RESTORED + 1))
|
|
else
|
|
FAILED=$((FAILED + 1))
|
|
fi
|
|
fi
|
|
done
|
|
;;
|
|
retroarch-rmp)
|
|
for rmp_file in "${TMP_DIR}/.config/retroarch/"*.rmp; do
|
|
if [[ -f "$rmp_file" ]]; then
|
|
filename=$(basename "$rmp_file")
|
|
if upload_file "$rmp_file" \
|
|
".config/retroarch/${filename}" \
|
|
"$ROCKNIX_HOST" "$ROCKNIX_USER" &>/dev/null; then
|
|
RESTORED=$((RESTORED + 1))
|
|
else
|
|
FAILED=$((FAILED + 1))
|
|
fi
|
|
fi
|
|
done
|
|
;;
|
|
retroarch-config)
|
|
if [[ -d "${TMP_DIR}/.config/retroarch/config/" ]]; then
|
|
if upload_dir "${TMP_DIR}/.config/retroarch/config/" \
|
|
".config/retroarch/config/" \
|
|
"$ROCKNIX_HOST" "$ROCKNIX_USER" &>/dev/null; then
|
|
RESTORED=$((RESTORED + 1))
|
|
else
|
|
FAILED=$((FAILED + 1))
|
|
log WARN "Error restoring config/"
|
|
fi
|
|
fi
|
|
;;
|
|
shaders)
|
|
if [[ -d "${TMP_DIR}/shaders/" ]]; then
|
|
if upload_dir "${TMP_DIR}/shaders/" \
|
|
"shaders/" \
|
|
"$ROCKNIX_HOST" "$ROCKNIX_USER" &>/dev/null; then
|
|
RESTORED=$((RESTORED + 1))
|
|
else
|
|
FAILED=$((FAILED + 1))
|
|
log WARN "Error restoring shaders/"
|
|
fi
|
|
fi
|
|
;;
|
|
ppsspp)
|
|
if [[ -f "${TMP_DIR}/.config/ppsspp/PSP/SYSTEM/ppsspp.ini" ]]; then
|
|
upload_file "${TMP_DIR}/.config/ppsspp/PSP/SYSTEM/ppsspp.ini" \
|
|
".config/ppsspp/PSP/SYSTEM/ppsspp.ini" \
|
|
"$ROCKNIX_HOST" "$ROCKNIX_USER" 2>/dev/null && RESTORED=$((RESTORED + 1)) || FAILED=$((FAILED + 1))
|
|
fi
|
|
if [[ -f "${TMP_DIR}/.config/ppsspp/PSP/SYSTEM/controls.ini" ]]; then
|
|
upload_file "${TMP_DIR}/.config/ppsspp/PSP/SYSTEM/controls.ini" \
|
|
".config/ppsspp/PSP/SYSTEM/controls.ini" \
|
|
"$ROCKNIX_HOST" "$ROCKNIX_USER" 2>/dev/null && RESTORED=$((RESTORED + 1)) || FAILED=$((FAILED + 1))
|
|
fi
|
|
;;
|
|
drastic)
|
|
if [[ -d "${TMP_DIR}/.config/drastic/config/" ]]; then
|
|
if upload_dir "${TMP_DIR}/.config/drastic/config/" \
|
|
".config/drastic/config/" \
|
|
"$ROCKNIX_HOST" "$ROCKNIX_USER" &>/dev/null; then
|
|
RESTORED=$((RESTORED + 1))
|
|
else
|
|
FAILED=$((FAILED + 1))
|
|
log WARN "Error restoring drastic/config/"
|
|
fi
|
|
fi
|
|
;;
|
|
other-emu)
|
|
for emu_path in ".config/game/configs" ".config/flycast" ".config/duckstation" ".config/yabasanshiro"; do
|
|
if [[ -e "${TMP_DIR}/${emu_path}" ]]; then
|
|
upload_dir "${TMP_DIR}/${emu_path}/" "${emu_path}/" \
|
|
"$ROCKNIX_HOST" "$ROCKNIX_USER" 2>/dev/null && RESTORED=$((RESTORED + 1)) || FAILED=$((FAILED + 1))
|
|
fi
|
|
done
|
|
;;
|
|
esac
|
|
done
|
|
|
|
# Clean up temporary safety backup
|
|
cleanup_tmp "${SAFETY_DIR}" 2>/dev/null || true
|
|
|
|
# Summary
|
|
echo ""
|
|
echo -e "${GREEN}========================================${NC}"
|
|
echo -e "${GREEN} Restore completed${NC}"
|
|
echo -e "${GREEN}========================================${NC}"
|
|
echo ""
|
|
echo -e " Device: ${CYAN}${DEVICE}${NC}"
|
|
echo -e " Restored: ${CYAN}${RESTORED}${NC}"
|
|
if [[ $FAILED -gt 0 ]]; then
|
|
echo -e " Failed: ${RED}${FAILED}${NC}"
|
|
fi
|
|
echo ""
|
|
echo -e " ${YELLOW}Note: Restart the console to apply changes${NC}"
|
|
echo ""
|