2026-01-25 12:40:04 +00:00
|
|
|
#!/bin/sh
|
|
|
|
|
|
|
|
|
|
HNAME=$(uci get system.@system[0].hostname)
|
|
|
|
|
DATE=$(date +%Y-%m-%d_%H-%M)
|
|
|
|
|
|
|
|
|
|
S_MOUNT="/tmp/share"
|
|
|
|
|
S_ADDR="nfs.lan:/mnt/media1/backup"
|
|
|
|
|
|
|
|
|
|
C_LIST="
|
|
|
|
|
/etc/config/
|
|
|
|
|
/etc/xray/
|
|
|
|
|
/etc/unbound/
|
|
|
|
|
/root/.ssh/
|
|
|
|
|
/opt/xray-config/
|
|
|
|
|
/opt/backup-manager/
|
|
|
|
|
"
|
|
|
|
|
|
|
|
|
|
H_REPLACE="wpad dnsmasq"
|
|
|
|
|
|
|
|
|
|
DIR="/opt/backup-manager"
|
|
|
|
|
SCR_BACKUP="$DIR/backup-configs.sh"
|
|
|
|
|
SCR_OPKG="$DIR/backup-opkg.sh"
|
|
|
|
|
|
2026-01-25 12:46:20 +00:00
|
|
|
check_dependencies() {
|
|
|
|
|
echo "--- Checking NFS dependencies ---"
|
|
|
|
|
local missing=""
|
|
|
|
|
local pkgs="kmod-fs-nfs kmod-fs-nfs-v3 kmod-fs-nfs-v4 nfs-utils"
|
|
|
|
|
|
|
|
|
|
for pkg in $pkgs; do
|
|
|
|
|
if ! opkg list-installed | grep -q "^$pkg "; then
|
|
|
|
|
missing="$missing $pkg"
|
|
|
|
|
fi
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
if [ -n "$missing" ]; then
|
|
|
|
|
echo " [!] Missing packages:$missing"
|
|
|
|
|
printf "Would you like to install them now? (y/n): "
|
|
|
|
|
read ans
|
|
|
|
|
if [ "$ans" = "y" ] || [ "$ans" = "Y" ]; then
|
|
|
|
|
echo "Updating package lists..."
|
|
|
|
|
opkg update >/dev/null 2>&1
|
|
|
|
|
for m in $missing; do
|
|
|
|
|
printf " [+] Installing $m... "
|
|
|
|
|
if opkg install "$m" >/dev/null 2>&1; then
|
|
|
|
|
echo "OK"
|
|
|
|
|
else
|
|
|
|
|
echo "FAILED"
|
|
|
|
|
return 1
|
|
|
|
|
fi
|
|
|
|
|
done
|
|
|
|
|
/sbin/depmod >/dev/null 2>&1
|
|
|
|
|
else
|
|
|
|
|
echo "Error: Cannot proceed without NFS dependencies."
|
|
|
|
|
return 1
|
|
|
|
|
fi
|
|
|
|
|
fi
|
|
|
|
|
echo " [+] All dependencies are satisfied."
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-25 12:40:04 +00:00
|
|
|
mount_share() {
|
|
|
|
|
mkdir -p "$S_MOUNT"
|
|
|
|
|
mount -t nfs "$S_ADDR" "$S_MOUNT" -o nolock,tcp >/dev/null 2>&1
|
|
|
|
|
if ! grep -qs "$S_MOUNT" /proc/mounts; then
|
|
|
|
|
echo "Error: Failed to mount NFS share ($S_ADDR)"
|
|
|
|
|
return 1
|
|
|
|
|
fi
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-25 12:46:20 +00:00
|
|
|
check_nfs_write() {
|
|
|
|
|
echo "--- Testing NFS Write/Read access ---"
|
|
|
|
|
mount_share || return 1
|
|
|
|
|
|
|
|
|
|
local test_file="$S_MOUNT/.nfs_test_$(date +%s)"
|
|
|
|
|
|
|
|
|
|
if ! touch "$test_file" >/dev/null 2>&1; then
|
|
|
|
|
echo " Error: Cannot write to NFS share (Read-only?)"
|
|
|
|
|
umount "$S_MOUNT"
|
|
|
|
|
return 1
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if ! cat "$test_file" >/dev/null 2>&1; then
|
|
|
|
|
echo " Error: Cannot read from NFS share"
|
|
|
|
|
rm -f "$test_file"
|
|
|
|
|
umount "$S_MOUNT"
|
|
|
|
|
return 1
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
rm -f "$test_file"
|
|
|
|
|
echo " [+] NFS Write/Read test passed."
|
|
|
|
|
umount "$S_MOUNT"
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-25 12:40:04 +00:00
|
|
|
clean_old_backups() {
|
|
|
|
|
mount_share || return 1
|
|
|
|
|
echo "--- Cleaning up backups older than 30 days ---"
|
|
|
|
|
|
|
|
|
|
find "$S_MOUNT" -maxdepth 1 -type f \( -name "*.tar.gz" -o -name "*.lst" \) -mtime +30 -exec rm -f {} \;
|
|
|
|
|
|
|
|
|
|
echo "Cleanup complete."
|
|
|
|
|
umount "$S_MOUNT"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
select_remote_file() {
|
|
|
|
|
local ext="$1"
|
2026-01-25 12:46:20 +00:00
|
|
|
|
|
|
|
|
check_dependencies || exit 1
|
|
|
|
|
check_nfs_write || exit 1
|
2026-01-25 12:40:04 +00:00
|
|
|
mount_share || return 1
|
|
|
|
|
|
|
|
|
|
echo "--- Select $ext file from NFS ---" >&2
|
|
|
|
|
FILES=$(find "$S_MOUNT" -maxdepth 1 -name "*$ext" | sort -r)
|
|
|
|
|
|
|
|
|
|
if [ -z "$FILES" ]; then
|
|
|
|
|
echo "No $ext files found." >&2
|
|
|
|
|
umount "$S_MOUNT"
|
|
|
|
|
return 1
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
i=1
|
|
|
|
|
for f in $FILES; do
|
|
|
|
|
size=$(du -sh "$f" | awk '{print $1}')
|
|
|
|
|
echo " [$i] $(basename "$f") ($size)" >&2
|
|
|
|
|
i=$((i+1))
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
printf "Selection (0 to cancel): " >&2
|
|
|
|
|
read choice
|
|
|
|
|
|
|
|
|
|
if [ -z "$choice" ] || [ "$choice" -eq 0 ] || [ "$choice" -ge "$i" ]; then
|
|
|
|
|
echo "Cancelled." >&2
|
|
|
|
|
umount "$S_MOUNT"
|
|
|
|
|
return 1
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
SELECTED=$(echo "$FILES" | sed -n "${choice}p")
|
|
|
|
|
|
|
|
|
|
RET_PATH="/tmp/restore_target$ext"
|
|
|
|
|
cp "$SELECTED" "$RET_PATH"
|
|
|
|
|
|
|
|
|
|
umount "$S_MOUNT"
|
|
|
|
|
SELECTED_PATH="$RET_PATH"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case "$1" in
|
|
|
|
|
backup)
|
|
|
|
|
echo "--- Remote Backup Starting ---"
|
2026-01-25 12:46:20 +00:00
|
|
|
|
|
|
|
|
check_dependencies || exit 1
|
|
|
|
|
check_nfs_write || exit 1
|
2026-01-25 12:40:04 +00:00
|
|
|
mount_share || exit 1
|
|
|
|
|
|
|
|
|
|
REMOTE_BACKUP="$S_MOUNT/backup_${HNAME}_${DATE}.tar.gz"
|
|
|
|
|
REMOTE_LIST="$S_MOUNT/packages_${HNAME}_${DATE}.lst"
|
|
|
|
|
|
|
|
|
|
$SCR_BACKUP "$REMOTE_BACKUP" "$REMOTE_LIST" "$SCR_OPKG" "$C_LIST" "$H_REPLACE"
|
|
|
|
|
|
|
|
|
|
sync
|
|
|
|
|
umount "$S_MOUNT"
|
|
|
|
|
echo "--- Backup Successfully Saved to NFS ---"
|
|
|
|
|
|
|
|
|
|
clean_old_backups
|
|
|
|
|
;;
|
|
|
|
|
|
|
|
|
|
restore-pkgs)
|
|
|
|
|
SELECTED_PATH=""
|
|
|
|
|
select_remote_file ".lst"
|
|
|
|
|
if [ -n "$SELECTED_PATH" ] && [ -f "$SELECTED_PATH" ]; then
|
|
|
|
|
echo "Restoring packages from $SELECTED_PATH..."
|
|
|
|
|
$SCR_OPKG restore "$SELECTED_PATH" "$H_REPLACE"
|
|
|
|
|
rm "$SELECTED_PATH"
|
|
|
|
|
fi
|
|
|
|
|
;;
|
|
|
|
|
|
|
|
|
|
restore-sys)
|
|
|
|
|
SELECTED_PATH=""
|
|
|
|
|
select_remote_file ".tar.gz"
|
|
|
|
|
if [ -n "$SELECTED_PATH" ] && [ -f "$SELECTED_PATH" ]; then
|
|
|
|
|
echo "Restoring system from $SELECTED_PATH..."
|
|
|
|
|
sysupgrade -r "$SELECTED_PATH"
|
|
|
|
|
echo "Restore complete. Reboot is recommended."
|
|
|
|
|
fi
|
|
|
|
|
;;
|
|
|
|
|
*)
|
|
|
|
|
echo "Usage: $0 {backup|restore-pkgs|restore-sys}"
|
|
|
|
|
exit 1
|
|
|
|
|
;;
|
|
|
|
|
esac
|