344 lines
9.4 KiB
Bash
Executable File
344 lines
9.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# lib-common.sh - Shared functions for ROCKNIX backup/restore
|
|
|
|
set -euo pipefail
|
|
|
|
# Script directory
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
|
|
# Load configuration
|
|
source "$SCRIPT_DIR/config.sh"
|
|
|
|
# Resolve BACKUP_DIR relative to script
|
|
case "$BACKUP_DIR" in
|
|
/*) ;; # Absolute path, do nothing
|
|
*) BACKUP_DIR="${SCRIPT_DIR}/${BACKUP_DIR}" ;;
|
|
esac
|
|
|
|
# Colores
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
CYAN='\033[0;36m'
|
|
NC='\033[0m' # No Color
|
|
|
|
# Logging
|
|
log() {
|
|
local level="$1"
|
|
shift
|
|
local msg="$*"
|
|
local timestamp
|
|
timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
|
|
|
case "$level" in
|
|
INFO) echo -e "${GREEN}[${timestamp}] INFO:${NC} $msg" ;;
|
|
WARN) echo -e "${YELLOW}[${timestamp}] WARN:${NC} $msg" ;;
|
|
ERROR) echo -e "${RED}[${timestamp}] ERROR:${NC} $msg" >&2 ;;
|
|
DEBUG) echo -e "${BLUE}[${timestamp}] DEBUG:${NC} $msg" ;;
|
|
esac
|
|
}
|
|
|
|
# Check dependencies
|
|
check_deps() {
|
|
local missing=()
|
|
for dep in tar dialog rsync sshpass; do
|
|
if ! command -v "$dep" &>/dev/null; then
|
|
missing+=("$dep")
|
|
fi
|
|
done
|
|
|
|
if [[ ${#missing[@]} -gt 0 ]]; then
|
|
log ERROR "Missing dependencies: ${missing[*]}"
|
|
log INFO "Install with: sudo dnf install ${missing[*]}"
|
|
return 1
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
# Ask for password if not configured
|
|
ask_password() {
|
|
if [[ -z "$ROCKNIX_PASSWORD" ]]; then
|
|
read -s -p "Password for ${ROCKNIX_USER}@${ROCKNIX_HOST}: " ROCKNIX_PASSWORD
|
|
echo ""
|
|
if [[ -z "$ROCKNIX_PASSWORD" ]]; then
|
|
log ERROR "Empty password"
|
|
return 1
|
|
fi
|
|
fi
|
|
export ROCKNIX_PASSWORD
|
|
}
|
|
|
|
# Build SSH connection string
|
|
ssh_target() {
|
|
local host="${1:-$ROCKNIX_HOST}"
|
|
local user="${2:-$ROCKNIX_USER}"
|
|
echo "${user}@${host}"
|
|
}
|
|
|
|
# Verify SSH connection
|
|
ssh_check() {
|
|
local host="${1:-$ROCKNIX_HOST}"
|
|
local user="${2:-$ROCKNIX_USER}"
|
|
local target
|
|
target=$(ssh_target "$host" "$user")
|
|
|
|
log INFO "Checking connection to ${target}..."
|
|
|
|
if [[ -n "$ROCKNIX_PASSWORD" ]]; then
|
|
if sshpass -p "$ROCKNIX_PASSWORD" ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=no "$target" "echo ok" &>/dev/null; then
|
|
log INFO "Connection successful"
|
|
return 0
|
|
fi
|
|
else
|
|
if ssh -o ConnectTimeout=5 -o BatchMode=yes "$target" "echo ok" &>/dev/null; then
|
|
log INFO "Connection successful"
|
|
return 0
|
|
fi
|
|
fi
|
|
|
|
log ERROR "Could not connect to ${target}"
|
|
log INFO "Make sure SSH is enabled on the ROCKNIX console"
|
|
return 1
|
|
}
|
|
|
|
# Execute remote command
|
|
remote_exec() {
|
|
local cmd="$1"
|
|
local host="${2:-$ROCKNIX_HOST}"
|
|
local user="${3:-$ROCKNIX_USER}"
|
|
local target
|
|
target=$(ssh_target "$host" "$user")
|
|
|
|
if [[ -n "$ROCKNIX_PASSWORD" ]]; then
|
|
sshpass -p "$ROCKNIX_PASSWORD" ssh -o ConnectTimeout=10 -o StrictHostKeyChecking=no "$target" "$cmd" 2>&1
|
|
else
|
|
ssh -o ConnectTimeout=10 "$target" "$cmd" 2>&1
|
|
fi
|
|
}
|
|
|
|
# List remote files
|
|
remote_list() {
|
|
local remote_path="$1"
|
|
local host="${2:-$ROCKNIX_HOST}"
|
|
local user="${3:-$ROCKNIX_USER}"
|
|
|
|
remote_exec "ls -la ${ROCKNIX_STORAGE}/${remote_path}/ 2>/dev/null" "$host" "$user"
|
|
}
|
|
|
|
# Download entire directory via rsync
|
|
download_dir() {
|
|
local remote_path="$1"
|
|
local local_path="$2"
|
|
local host="${3:-$ROCKNIX_HOST}"
|
|
local user="${4:-$ROCKNIX_USER}"
|
|
local target
|
|
target=$(ssh_target "$host" "$user")
|
|
|
|
mkdir -p "$local_path"
|
|
|
|
local rsync_opts=(-avz --timeout=30 -e "ssh -o StrictHostKeyChecking=no -o ConnectTimeout=10")
|
|
|
|
if [[ -n "$ROCKNIX_PASSWORD" ]]; then
|
|
sshpass -p "$ROCKNIX_PASSWORD" rsync "${rsync_opts[@]}" \
|
|
"${target}:${ROCKNIX_STORAGE}/${remote_path}/" \
|
|
"${local_path}/" 2>&1
|
|
else
|
|
rsync "${rsync_opts[@]}" \
|
|
"${target}:${ROCKNIX_STORAGE}/${remote_path}/" \
|
|
"${local_path}/" 2>&1
|
|
fi
|
|
}
|
|
|
|
# Upload entire directory via rsync
|
|
upload_dir() {
|
|
local local_path="$1"
|
|
local remote_path="$2"
|
|
local host="${3:-$ROCKNIX_HOST}"
|
|
local user="${4:-$ROCKNIX_USER}"
|
|
local target
|
|
target=$(ssh_target "$host" "$user")
|
|
|
|
local rsync_opts=(-avz --timeout=30 -e "ssh -o StrictHostKeyChecking=no -o ConnectTimeout=10")
|
|
|
|
if [[ -n "$ROCKNIX_PASSWORD" ]]; then
|
|
sshpass -p "$ROCKNIX_PASSWORD" rsync "${rsync_opts[@]}" \
|
|
"${local_path}/" \
|
|
"${target}:${ROCKNIX_STORAGE}/${remote_path}/" 2>&1
|
|
else
|
|
rsync "${rsync_opts[@]}" \
|
|
"${local_path}/" \
|
|
"${target}:${ROCKNIX_STORAGE}/${remote_path}/" 2>&1
|
|
fi
|
|
}
|
|
|
|
# Download a single file
|
|
download_file() {
|
|
local remote_file="$1"
|
|
local local_file="$2"
|
|
local host="${3:-$ROCKNIX_HOST}"
|
|
local user="${4:-$ROCKNIX_USER}"
|
|
local target
|
|
target=$(ssh_target "$host" "$user")
|
|
|
|
mkdir -p "$(dirname "$local_file")"
|
|
|
|
local rsync_opts=(-avz --timeout=30 -e "ssh -o StrictHostKeyChecking=no -o ConnectTimeout=10")
|
|
|
|
if [[ -n "$ROCKNIX_PASSWORD" ]]; then
|
|
sshpass -p "$ROCKNIX_PASSWORD" rsync "${rsync_opts[@]}" \
|
|
"${target}:${ROCKNIX_STORAGE}/${remote_file}" \
|
|
"${local_file}" 2>&1
|
|
else
|
|
rsync "${rsync_opts[@]}" \
|
|
"${target}:${ROCKNIX_STORAGE}/${remote_file}" \
|
|
"${local_file}" 2>&1
|
|
fi
|
|
}
|
|
|
|
# Upload a single file
|
|
upload_file() {
|
|
local local_file="$1"
|
|
local remote_file="$2"
|
|
local host="${3:-$ROCKNIX_HOST}"
|
|
local user="${4:-$ROCKNIX_USER}"
|
|
local target
|
|
target=$(ssh_target "$host" "$user")
|
|
|
|
local rsync_opts=(-avz --timeout=30 -e "ssh -o StrictHostKeyChecking=no -o ConnectTimeout=10")
|
|
|
|
if [[ -n "$ROCKNIX_PASSWORD" ]]; then
|
|
sshpass -p "$ROCKNIX_PASSWORD" rsync "${rsync_opts[@]}" \
|
|
"${local_file}" \
|
|
"${target}:${ROCKNIX_STORAGE}/${remote_file}" 2>&1
|
|
else
|
|
rsync "${rsync_opts[@]}" \
|
|
"${local_file}" \
|
|
"${target}:${ROCKNIX_STORAGE}/${remote_file}" 2>&1
|
|
fi
|
|
}
|
|
|
|
# Direct backup via tar over SSH (no temporary files)
|
|
backup_via_ssh() {
|
|
local files=("$@")
|
|
local host="${ROCKNIX_HOST}"
|
|
local user="${ROCKNIX_USER}"
|
|
local target
|
|
target=$(ssh_target "$host" "$user")
|
|
|
|
# Build remote tar command
|
|
local tar_args=""
|
|
for file in "${files[@]}"; do
|
|
tar_args="${tar_args} ${ROCKNIX_STORAGE}/${file}"
|
|
done
|
|
|
|
# Execute remote tar and compress locally
|
|
if [[ -n "$ROCKNIX_PASSWORD" ]]; then
|
|
sshpass -p "$ROCKNIX_PASSWORD" ssh -o ConnectTimeout=10 -o StrictHostKeyChecking=no "$target" \
|
|
"tar czf - -C ${ROCKNIX_STORAGE} ${tar_args}" 2>/dev/null
|
|
else
|
|
ssh -o ConnectTimeout=10 "$target" \
|
|
"tar czf - -C ${ROCKNIX_STORAGE} ${tar_args}" 2>/dev/null
|
|
fi
|
|
}
|
|
|
|
# Detect ROCKNIX device
|
|
detect_device() {
|
|
local host="${1:-$ROCKNIX_HOST}"
|
|
local user="${2:-$ROCKNIX_USER}"
|
|
local target
|
|
target=$(ssh_target "$host" "$user")
|
|
|
|
log INFO "Detecting device..." >&2
|
|
|
|
local device_info
|
|
if [[ -n "$ROCKNIX_PASSWORD" ]]; then
|
|
device_info=$(sshpass -p "$ROCKNIX_PASSWORD" ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=no "$target" \
|
|
"cat ${ROCKNIX_STORAGE}/device_info_ROCKNIX_*.txt 2>/dev/null" 2>/dev/null || true)
|
|
else
|
|
device_info=$(ssh -o ConnectTimeout=5 "$target" \
|
|
"cat ${ROCKNIX_STORAGE}/device_info_ROCKNIX_*.txt 2>/dev/null" 2>/dev/null || true)
|
|
fi
|
|
|
|
if [[ -n "$device_info" ]]; then
|
|
local device_name
|
|
device_name=$(echo "$device_info" | grep "^DEVICE_NAME=" | cut -d'=' -f2 | tr -d '"')
|
|
local cfw_version
|
|
cfw_version=$(echo "$device_info" | grep "^CFW_VERSION=" | cut -d'=' -f2 | tr -d '"')
|
|
|
|
if [[ -n "$device_name" ]]; then
|
|
log INFO "Device: ${device_name} (ROCKNIX ${cfw_version})" >&2
|
|
echo "${device_name}"
|
|
return 0
|
|
fi
|
|
fi
|
|
|
|
log WARN "Could not detect device" >&2
|
|
echo "Unknown"
|
|
return 1
|
|
}
|
|
|
|
# Create temporary directory
|
|
create_tmp_dir() {
|
|
local prefix="${1:-rocknix-backup}"
|
|
local tmp_dir
|
|
tmp_dir=$(mktemp -d "/tmp/${prefix}-XXXXXX")
|
|
echo "$tmp_dir"
|
|
}
|
|
|
|
# Clean up temporary directory
|
|
cleanup_tmp() {
|
|
local tmp_dir="$1"
|
|
if [[ -d "$tmp_dir" ]]; then
|
|
rm -rf "$tmp_dir"
|
|
fi
|
|
}
|
|
|
|
# Get human-readable size
|
|
human_size() {
|
|
local bytes="$1"
|
|
if [[ $bytes -ge 1073741824 ]]; then
|
|
echo "$(echo "scale=1; $bytes/1073741824" | bc)G"
|
|
elif [[ $bytes -ge 1048576 ]]; then
|
|
echo "$(echo "scale=1; $bytes/1048576" | bc)M"
|
|
elif [[ $bytes -ge 1024 ]]; then
|
|
echo "$(echo "scale=1; $bytes/1024" | bc)K"
|
|
else
|
|
echo "${bytes}B"
|
|
fi
|
|
}
|
|
|
|
# Filter device-specific settings from file
|
|
filter_specific_settings() {
|
|
local input_file="$1"
|
|
local output_file="$2"
|
|
|
|
cp "$input_file" "$output_file"
|
|
|
|
for setting in "${GENERIC_SETTINGS_FILTER[@]}"; do
|
|
sed -i "/^${setting} = /d" "$output_file"
|
|
done
|
|
}
|
|
|
|
# Show contents of a backup file
|
|
show_backup_contents() {
|
|
local backup_file="$1"
|
|
|
|
if [[ ! -f "$backup_file" ]]; then
|
|
log ERROR "File not found: $backup_file"
|
|
return 1
|
|
fi
|
|
|
|
echo ""
|
|
log INFO "Backup contents:"
|
|
tar -tzf "$backup_file" | head -50
|
|
|
|
local total_files
|
|
total_files=$(tar -tzf "$backup_file" | wc -l)
|
|
local total_size
|
|
total_size=$(du -h "$backup_file" | cut -f1)
|
|
|
|
echo ""
|
|
echo -e "${CYAN}Total: ${total_files} archivos, ${total_size}${NC}"
|
|
}
|