2026-01-25 12:40:04 +00:00
|
|
|
#!/bin/sh
|
|
|
|
|
|
2026-04-14 13:16:43 +04:00
|
|
|
DIR=$(cd "$(dirname "$0")" && pwd)
|
|
|
|
|
ENV_FILE="$DIR/.env"
|
2026-02-04 04:05:30 +04:00
|
|
|
|
2026-04-14 13:16:43 +04:00
|
|
|
if [ -f "$ENV_FILE" ]; then
|
|
|
|
|
. "$ENV_FILE"
|
|
|
|
|
else
|
|
|
|
|
echo " [!] Error: .env file not found at $ENV_FILE"
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
2026-02-04 04:05:30 +04:00
|
|
|
|
2026-01-25 12:40:04 +00:00
|
|
|
HNAME=$(uci get system.@system[0].hostname)
|
|
|
|
|
DATE=$(date +%Y-%m-%d_%H-%M)
|
2026-02-04 04:05:30 +04:00
|
|
|
L_BACKUP_DIR="$DIR/local_backups"
|
2026-01-25 12:40:04 +00:00
|
|
|
SCR_BACKUP="$DIR/backup-configs.sh"
|
2026-04-13 15:07:22 +04:00
|
|
|
SCR_APK="$DIR/backup-apk.sh"
|
2026-01-25 12:40:04 +00:00
|
|
|
|
2026-02-04 04:05:30 +04:00
|
|
|
mkdir -p "$L_BACKUP_DIR"
|
|
|
|
|
|
|
|
|
|
if [ "$STORAGE_TYPE" = "nfs" ]; then
|
|
|
|
|
FULL_ADDR="${S_HOST}:${S_PATH}"
|
|
|
|
|
else
|
|
|
|
|
FULL_ADDR="//${S_HOST}${S_PATH}"
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
check_network() {
|
|
|
|
|
printf "Checking network %s... " "$S_HOST"
|
|
|
|
|
if ! ping -c 2 "$S_HOST" >/dev/null 2>&1; then
|
|
|
|
|
echo "FAILED"
|
2026-02-04 05:02:57 +04:00
|
|
|
echo " [!] Error: Remote host $S_HOST is unreachable."
|
2026-02-04 04:05:30 +04:00
|
|
|
return 1
|
|
|
|
|
fi
|
|
|
|
|
echo "OK"
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-25 12:46:20 +00:00
|
|
|
check_dependencies() {
|
2026-02-04 04:05:30 +04:00
|
|
|
printf "Checking %s dependencies... " "$STORAGE_TYPE"
|
|
|
|
|
local pkgs=""
|
2026-04-14 13:16:43 +04:00
|
|
|
[ "$STORAGE_TYPE" = "nfs" ] && pkgs="nfs-utils kmod-fs-nfs kmod-fs-nfs-v3 kmod-fs-nfs-v4"
|
2026-04-14 13:33:51 +04:00
|
|
|
[ "$STORAGE_TYPE" = "smb" ] && pkgs="cifsmount kmod-fs-cifs"
|
2026-04-13 15:07:22 +04:00
|
|
|
|
2026-01-25 12:46:20 +00:00
|
|
|
local missing=""
|
|
|
|
|
for pkg in $pkgs; do
|
2026-04-13 15:07:22 +04:00
|
|
|
if ! apk info -e "$pkg" >/dev/null 2>&1; then
|
|
|
|
|
missing="$missing $pkg"
|
|
|
|
|
fi
|
2026-01-25 12:46:20 +00:00
|
|
|
done
|
2026-04-13 15:07:22 +04:00
|
|
|
|
2026-01-25 12:46:20 +00:00
|
|
|
if [ -n "$missing" ]; then
|
2026-04-13 15:07:22 +04:00
|
|
|
echo "FAILED"
|
2026-02-04 04:05:30 +04:00
|
|
|
echo " [!] Missing: $missing. Install them to use remote backup."
|
|
|
|
|
return 1
|
2026-01-25 12:46:20 +00:00
|
|
|
fi
|
2026-02-04 04:05:30 +04:00
|
|
|
echo "OK"
|
2026-01-25 12:46:20 +00:00
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-25 12:40:04 +00:00
|
|
|
mount_share() {
|
|
|
|
|
mkdir -p "$S_MOUNT"
|
2026-02-04 04:05:30 +04:00
|
|
|
if grep -qs "$S_MOUNT" /proc/mounts; then
|
|
|
|
|
umount -l "$S_MOUNT" >/dev/null 2>&1
|
2026-01-25 12:40:04 +00:00
|
|
|
fi
|
2026-02-04 04:05:30 +04:00
|
|
|
printf "Mounting %s storage... " "$STORAGE_TYPE"
|
|
|
|
|
local mount_err
|
|
|
|
|
if [ "$STORAGE_TYPE" = "nfs" ]; then
|
|
|
|
|
mount_err=$(mount -t nfs "$FULL_ADDR" "$S_MOUNT" -o nolock,tcp 2>&1)
|
|
|
|
|
else
|
|
|
|
|
mount_err=$(mount -t cifs "$FULL_ADDR" "$S_MOUNT" -o user=$SMB_USER,pass=$SMB_PASS,vers=3.0,sec=ntlmssp 2>&1)
|
2026-01-25 12:46:20 +00:00
|
|
|
fi
|
2026-02-04 04:05:30 +04:00
|
|
|
if grep -qs "$S_MOUNT" /proc/mounts; then
|
|
|
|
|
echo "OK"
|
|
|
|
|
return 0
|
|
|
|
|
else
|
|
|
|
|
echo "FAILED"
|
2026-02-04 05:02:57 +04:00
|
|
|
echo " [!] Error: Failed to mount $STORAGE_TYPE ($FULL_ADDR)"
|
|
|
|
|
[ -n "$mount_err" ] && echo " System message: $mount_err"
|
2026-01-25 12:46:20 +00:00
|
|
|
return 1
|
|
|
|
|
fi
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-04 04:05:30 +04:00
|
|
|
manage_local_backups() {
|
|
|
|
|
printf "Cleaning up local storage (keeping last %s)... " "$LOCAL_KEEP"
|
|
|
|
|
local tail_val=$((LOCAL_KEEP + 1))
|
|
|
|
|
ls -t "$L_BACKUP_DIR"/*.tar.gz 2>/dev/null | tail -n +$tail_val | xargs rm -f
|
|
|
|
|
ls -t "$L_BACKUP_DIR"/*.lst 2>/dev/null | tail -n +$tail_val | xargs rm -f
|
|
|
|
|
echo "OK"
|
2026-01-25 12:40:04 +00:00
|
|
|
}
|
|
|
|
|
|
2026-02-04 04:05:30 +04:00
|
|
|
clean_old_remote_backups() {
|
|
|
|
|
printf "Cleaning up remote backups older than %s days... " "$HOST_KEEP"
|
|
|
|
|
find "$S_MOUNT" -maxdepth 1 -type f \( -name "*.tar.gz" -o -name "*.lst" \) -mtime +$HOST_KEEP -exec rm -f {} \;
|
|
|
|
|
echo "OK"
|
|
|
|
|
}
|
2026-01-25 12:40:04 +00:00
|
|
|
|
2026-02-04 04:05:30 +04:00
|
|
|
select_file() {
|
|
|
|
|
local search_dir="$1"
|
|
|
|
|
local ext="$2"
|
|
|
|
|
echo "Select $ext file" >&2
|
|
|
|
|
FILES=$(ls -t "$search_dir"/*"$ext" 2>/dev/null)
|
|
|
|
|
[ -z "$FILES" ] && return 1
|
2026-01-25 12:40:04 +00:00
|
|
|
i=1
|
|
|
|
|
for f in $FILES; do
|
2026-02-04 04:05:30 +04:00
|
|
|
echo " [$i] $(basename "$f") ($(du -sh "$f" | awk '{print $1}'))" >&2
|
2026-01-25 12:40:04 +00:00
|
|
|
i=$((i+1))
|
|
|
|
|
done
|
|
|
|
|
printf "Selection (0 to cancel): " >&2
|
|
|
|
|
read choice
|
2026-02-04 04:05:30 +04:00
|
|
|
[ -z "$choice" ] || [ "$choice" -eq 0 ] || [ "$choice" -ge "$i" ] && return 1
|
|
|
|
|
SELECTED_PATH=$(echo "$FILES" | sed -n "${choice}p")
|
2026-01-25 12:40:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case "$1" in
|
|
|
|
|
backup)
|
2026-02-04 04:05:30 +04:00
|
|
|
LOCAL_FILE="$L_BACKUP_DIR/backup_${HNAME}_${DATE}.tar.gz"
|
|
|
|
|
LOCAL_LST="$L_BACKUP_DIR/packages_${HNAME}_${DATE}.lst"
|
|
|
|
|
REMOTE_STATUS="FAILED"
|
2026-04-13 15:07:22 +04:00
|
|
|
$SCR_BACKUP "$LOCAL_FILE" "$LOCAL_LST" "$SCR_APK" "$C_LIST" "$H_REPLACE" "$C_EXCLUDE"
|
2026-02-04 04:05:30 +04:00
|
|
|
manage_local_backups
|
|
|
|
|
if check_network && check_dependencies && mount_share; then
|
|
|
|
|
printf "Copying to %s storage... " "$STORAGE_TYPE"
|
|
|
|
|
if cp "$LOCAL_FILE" "$LOCAL_LST" "$S_MOUNT/"; then
|
|
|
|
|
echo "OK"
|
|
|
|
|
REMOTE_STATUS="OK"
|
|
|
|
|
clean_old_remote_backups
|
|
|
|
|
else
|
|
|
|
|
echo "FAILED"
|
|
|
|
|
fi
|
|
|
|
|
sync
|
|
|
|
|
umount "$S_MOUNT"
|
|
|
|
|
else
|
2026-02-04 05:02:57 +04:00
|
|
|
echo " Backup remains only in $L_BACKUP_DIR"
|
2026-02-04 04:05:30 +04:00
|
|
|
fi
|
|
|
|
|
echo "Summary:"
|
2026-02-04 05:02:57 +04:00
|
|
|
echo " [+] Local backup: $LOCAL_FILE"
|
|
|
|
|
echo " [+] Local packages: $LOCAL_LST"
|
2026-02-04 04:05:30 +04:00
|
|
|
if [ "$REMOTE_STATUS" = "OK" ]; then
|
2026-02-04 05:02:57 +04:00
|
|
|
echo " [+] Remote backup: ${S_HOST}:${S_PATH}/$(basename "$LOCAL_FILE")"
|
|
|
|
|
echo " [+] Remote packages: ${S_HOST}:${S_PATH}/$(basename "$LOCAL_LST")"
|
2026-02-04 04:05:30 +04:00
|
|
|
else
|
|
|
|
|
echo " [!] Remote: Not saved"
|
|
|
|
|
fi
|
|
|
|
|
;;
|
|
|
|
|
|
|
|
|
|
restore)
|
2026-02-04 05:02:57 +04:00
|
|
|
echo " [1] Local storage ($L_BACKUP_DIR)"
|
|
|
|
|
echo " [2] Remote storage ($STORAGE_TYPE)"
|
2026-02-04 04:05:30 +04:00
|
|
|
printf "Select source: "
|
|
|
|
|
read s_choice
|
|
|
|
|
R_DIR=""
|
|
|
|
|
[ "$s_choice" -eq 1 ] && R_DIR="$L_BACKUP_DIR"
|
|
|
|
|
[ "$s_choice" -eq 2 ] && { check_network && mount_share && R_DIR="$S_MOUNT"; }
|
|
|
|
|
if [ -z "$R_DIR" ]; then
|
2026-02-04 05:02:57 +04:00
|
|
|
echo " Source unavailable or cancelled."
|
2026-02-04 04:05:30 +04:00
|
|
|
exit 1
|
2026-01-25 12:40:04 +00:00
|
|
|
fi
|
2026-02-04 05:02:57 +04:00
|
|
|
echo " [1] System configs (.tar.gz)"
|
|
|
|
|
echo " [2] Package list (.lst)"
|
2026-02-04 04:05:30 +04:00
|
|
|
printf "Select type: "
|
|
|
|
|
read t_choice
|
|
|
|
|
case "$t_choice" in
|
|
|
|
|
1)
|
|
|
|
|
select_file "$R_DIR" ".tar.gz"
|
|
|
|
|
if [ -n "$SELECTED_PATH" ]; then
|
|
|
|
|
[ "$s_choice" -eq 2 ] && { cp "$SELECTED_PATH" /tmp/restore.tar.gz; SELECTED_PATH="/tmp/restore.tar.gz"; umount "$S_MOUNT"; }
|
|
|
|
|
sysupgrade -r "$SELECTED_PATH"
|
2026-04-14 15:58:04 +04:00
|
|
|
echo "Summary:"
|
|
|
|
|
echo " [+] Restoring configs completed"
|
|
|
|
|
echo " [!] Reboot required"
|
2026-02-04 04:05:30 +04:00
|
|
|
fi
|
|
|
|
|
;;
|
|
|
|
|
2)
|
|
|
|
|
select_file "$R_DIR" ".lst"
|
|
|
|
|
if [ -n "$SELECTED_PATH" ]; then
|
2026-04-13 15:07:22 +04:00
|
|
|
$SCR_APK restore "$SELECTED_PATH" "$H_REPLACE"
|
2026-02-04 04:05:30 +04:00
|
|
|
fi
|
|
|
|
|
;;
|
|
|
|
|
*)
|
|
|
|
|
echo "Cancelled."
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
grep -qs "$S_MOUNT" /proc/mounts && umount "$S_MOUNT"
|
2026-01-25 12:40:04 +00:00
|
|
|
;;
|
2026-02-04 04:05:30 +04:00
|
|
|
|
2026-01-25 12:40:04 +00:00
|
|
|
*)
|
2026-02-04 04:05:30 +04:00
|
|
|
echo "Usage: $0 {backup|restore}"
|
2026-01-25 12:40:04 +00:00
|
|
|
exit 1
|
|
|
|
|
;;
|
|
|
|
|
esac
|