mirror of
https://github.com/Lakr233/vphone-cli.git
synced 2026-04-04 20:39:05 +08:00
add: VM backup, restore, and switch support (#206)
* fix: prefer project venv Python for patchers * add: VM backup, restore, and switch support Named backups via rsync --sparse for efficient sparse disk handling. - vm_backup.sh: save current VM as a named backup to vm.backups/ - vm_restore.sh: restore a named backup into vm/ - vm_switch.sh: save current + restore target in one step - Makefile targets: vm_backup, vm_restore, vm_switch, vm_list - Documentation added to all READMEs (EN, ZH, KO, JA) Closes #204 Made-with: Cursor
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -330,3 +330,4 @@ setup_logs/
|
||||
/research/artifacts
|
||||
/research/xnu
|
||||
/vm
|
||||
/vm.backups
|
||||
|
||||
45
Makefile
45
Makefile
@@ -7,6 +7,10 @@ VM_DIR ?= vm
|
||||
CPU ?= 8 # CPU cores (only used during vm_new)
|
||||
MEMORY ?= 8192 # Memory in MB (only used during vm_new)
|
||||
DISK_SIZE ?= 64 # Disk size in GB (only used during vm_new)
|
||||
BACKUPS_DIR ?= vm.backups
|
||||
NAME ?=
|
||||
BACKUP_INCLUDE_IPSW ?= 0
|
||||
FORCE ?= 0
|
||||
RESTORE_UDID ?= # UDID for restore operations
|
||||
RESTORE_ECID ?= # ECID for restore operations
|
||||
IRECOVERY_ECID ?= # ECID for irecovery operations
|
||||
@@ -62,6 +66,12 @@ help:
|
||||
@echo " CPU=8 CPU cores (stored in manifest)"
|
||||
@echo " MEMORY=8192 Memory in MB (stored in manifest)"
|
||||
@echo " DISK_SIZE=64 Disk size in GB (stored in manifest)"
|
||||
@echo " make vm_backup NAME=<name> Save current VM as a named backup"
|
||||
@echo " make vm_restore NAME=<name> Restore a named backup into vm/"
|
||||
@echo " make vm_switch NAME=<name> Save current + restore target (one step)"
|
||||
@echo " make vm_list List available backups"
|
||||
@echo " Options: BACKUP_INCLUDE_IPSW=1 Include *_Restore* IPSW dirs in backup"
|
||||
@echo " FORCE=1 Skip overwrite prompt on restore"
|
||||
@echo " make amfidont_allow_vphone Start amfidont for the signed vphone-cli binary"
|
||||
@echo " make boot_host_preflight Diagnose whether host can launch signed PV=3 binary"
|
||||
@echo " make boot Boot VM (reads from config.plist)"
|
||||
@@ -183,12 +193,45 @@ vphoned:
|
||||
# VM management
|
||||
# ═══════════════════════════════════════════════════════════════════
|
||||
|
||||
.PHONY: vm_new amfidont_allow_vphone boot_host_preflight boot boot_dfu boot_binary_check
|
||||
.PHONY: vm_new vm_backup vm_restore vm_switch vm_list amfidont_allow_vphone boot_host_preflight boot boot_dfu boot_binary_check
|
||||
|
||||
vm_new:
|
||||
CPU="$(CPU)" MEMORY="$(MEMORY)" \
|
||||
zsh $(SCRIPTS)/vm_create.sh --dir $(VM_DIR) --disk-size $(DISK_SIZE)
|
||||
|
||||
vm_backup:
|
||||
VM_DIR="$(VM_DIR)" BACKUPS_DIR="$(BACKUPS_DIR)" NAME="$(NAME)" BACKUP_INCLUDE_IPSW="$(BACKUP_INCLUDE_IPSW)" \
|
||||
zsh $(SCRIPTS)/vm_backup.sh
|
||||
|
||||
vm_restore:
|
||||
VM_DIR="$(VM_DIR)" BACKUPS_DIR="$(BACKUPS_DIR)" NAME="$(NAME)" FORCE="$(FORCE)" \
|
||||
zsh $(SCRIPTS)/vm_restore.sh
|
||||
|
||||
vm_switch:
|
||||
VM_DIR="$(VM_DIR)" BACKUPS_DIR="$(BACKUPS_DIR)" NAME="$(NAME)" BACKUP_INCLUDE_IPSW="$(BACKUP_INCLUDE_IPSW)" \
|
||||
zsh $(SCRIPTS)/vm_switch.sh
|
||||
|
||||
vm_list:
|
||||
@if [ -d "$(BACKUPS_DIR)" ]; then \
|
||||
current=""; \
|
||||
[ -f "$(VM_DIR)/.vm_name" ] && current="$$(cat "$(VM_DIR)/.vm_name")"; \
|
||||
found=0; \
|
||||
for d in "$(BACKUPS_DIR)"/*/; do \
|
||||
[ -f "$${d}config.plist" ] || continue; \
|
||||
name="$$(basename "$$d")"; \
|
||||
size="$$(du -sh "$$d" 2>/dev/null | cut -f1)"; \
|
||||
if [ "$$name" = "$$current" ]; then \
|
||||
echo " * $$name ($$size) [active]"; \
|
||||
else \
|
||||
echo " $$name ($$size)"; \
|
||||
fi; \
|
||||
found=1; \
|
||||
done; \
|
||||
[ "$$found" = "0" ] && echo " (no backups yet — run: make vm_backup NAME=<name>)"; \
|
||||
else \
|
||||
echo " (no backups yet — run: make vm_backup NAME=<name>)"; \
|
||||
fi
|
||||
|
||||
amfidont_allow_vphone: bundle
|
||||
zsh $(SCRIPTS)/start_amfidont_for_vphone.sh
|
||||
|
||||
|
||||
15
README.md
15
README.md
@@ -218,6 +218,21 @@ Connect via:
|
||||
- **VNC:** `vnc://127.0.0.1:5901`
|
||||
- [**RPC:**](http://github.com/doronz88/rpc-project) `rpcclient -p 5910 127.0.0.1`
|
||||
|
||||
## VM Backup & Switch
|
||||
|
||||
Save and switch between multiple VM environments (e.g. different iOS builds or firmware variants). Backups are stored in `vm.backups/` using `rsync --sparse` for efficient sparse disk handling.
|
||||
|
||||
```bash
|
||||
make vm_backup NAME=26.1-clean # save current VM
|
||||
rm -rf vm && make vm_new # start fresh for a different build
|
||||
# ... fw_prepare, fw_patch, restore, cfw_install, boot
|
||||
make vm_backup NAME=26.3-jb # save the new one too
|
||||
make vm_list # list all saved backups
|
||||
make vm_switch NAME=26.1-clean # swap between them
|
||||
```
|
||||
|
||||
> **Note:** Always stop the VM before backup/switch/restore.
|
||||
|
||||
## FAQ
|
||||
|
||||
> **Before anything else — run `git pull` to make sure you have the latest version.**
|
||||
|
||||
@@ -209,6 +209,21 @@ iproxy 5910 5910 # RPC
|
||||
- **VNC:** `vnc://127.0.0.1:5901`
|
||||
- [**RPC:**](http://github.com/doronz88/rpc-project) `rpcclient -p 5910 127.0.0.1`
|
||||
|
||||
## VM バックアップと切り替え
|
||||
|
||||
複数の VM 環境(異なる iOS ビルドやファームウェアバリアントなど)を保存して切り替えることができます。バックアップは `vm.backups/` に保存され、`rsync --sparse` でスパースディスクイメージを効率的に処理します。
|
||||
|
||||
```bash
|
||||
make vm_backup NAME=26.1-clean # 現在の VM を保存
|
||||
rm -rf vm && make vm_new # 新しいビルド用に初期化
|
||||
# ... fw_prepare, fw_patch, restore, cfw_install, boot
|
||||
make vm_backup NAME=26.3-jb # 新しい VM も保存
|
||||
make vm_list # すべてのバックアップを一覧表示
|
||||
make vm_switch NAME=26.1-clean # バックアップ間を切り替え
|
||||
```
|
||||
|
||||
> **注意:** バックアップ/切り替え/復元の前に必ず VM を停止してください。
|
||||
|
||||
## よくある質問 (FAQ)
|
||||
|
||||
> **何よりもまず — `git pull` を実行して最新バージョンであることを確認してください**
|
||||
|
||||
@@ -209,6 +209,21 @@ iproxy 5910 5910 # RPC
|
||||
- **VNC:** `vnc://127.0.0.1:5901`
|
||||
- [**RPC:**](http://github.com/doronz88/rpc-project) `rpcclient -p 5910 127.0.0.1`
|
||||
|
||||
## VM 백업 및 전환
|
||||
|
||||
여러 VM 환경(예: 다른 iOS 빌드 또는 펌웨어 변형)을 저장하고 전환할 수 있습니다. 백업은 `vm.backups/`에 저장되며 `rsync --sparse`를 사용하여 희소 디스크 이미지를 효율적으로 처리합니다.
|
||||
|
||||
```bash
|
||||
make vm_backup NAME=26.1-clean # 현재 VM 저장
|
||||
rm -rf vm && make vm_new # 새로운 빌드를 위해 초기화
|
||||
# ... fw_prepare, fw_patch, restore, cfw_install, boot
|
||||
make vm_backup NAME=26.3-jb # 새 VM도 저장
|
||||
make vm_list # 모든 백업 목록 보기
|
||||
make vm_switch NAME=26.1-clean # 백업 간 전환
|
||||
```
|
||||
|
||||
> **참고:** 백업/전환/복원 전에 반드시 VM을 중지하세요.
|
||||
|
||||
## FAQ
|
||||
|
||||
> **무엇보다 먼저 — `git pull`을 실행하여 최신 버전인지 확인하세요.**
|
||||
|
||||
@@ -209,6 +209,21 @@ iproxy 5910 5910 # RPC
|
||||
- **VNC:** `vnc://127.0.0.1:5901`
|
||||
- [**RPC:**](http://github.com/doronz88/rpc-project) `rpcclient -p 5910 127.0.0.1`
|
||||
|
||||
## VM 备份与切换
|
||||
|
||||
保存并切换多个 VM 环境(例如不同的 iOS 构建版本或固件变体)。备份存储在 `vm.backups/` 下,使用 `rsync --sparse` 高效处理稀疏磁盘镜像。
|
||||
|
||||
```bash
|
||||
make vm_backup NAME=26.1-clean # 保存当前 VM
|
||||
rm -rf vm && make vm_new # 清空后从新构建开始
|
||||
# ... fw_prepare, fw_patch, restore, cfw_install, boot
|
||||
make vm_backup NAME=26.3-jb # 保存新的 VM
|
||||
make vm_list # 列出所有备份
|
||||
make vm_switch NAME=26.1-clean # 在不同备份之间切换
|
||||
```
|
||||
|
||||
> **注意:** 备份/切换/恢复前请先停止 VM。
|
||||
|
||||
## 常见问题(FAQ)
|
||||
|
||||
> **在做其他任何事情之前——先运行 `git pull` 确保你有最新版。**
|
||||
|
||||
95
scripts/vm_backup.sh
Executable file
95
scripts/vm_backup.sh
Executable file
@@ -0,0 +1,95 @@
|
||||
#!/bin/zsh
|
||||
# vm_backup.sh — Save the current VM as a named backup.
|
||||
#
|
||||
# Backups are stored under vm.backups/<name>/ using rsync --sparse.
|
||||
# The active VM remembers its name in vm/.vm_name for use by vm_switch.
|
||||
#
|
||||
# Usage:
|
||||
# make vm_backup NAME=ios17
|
||||
# make vm_backup NAME=ios18-jb BACKUP_INCLUDE_IPSW=1
|
||||
set -euo pipefail
|
||||
|
||||
VM_DIR="${VM_DIR:-vm}"
|
||||
BACKUPS_DIR="${BACKUPS_DIR:-vm.backups}"
|
||||
NAME="${NAME:-}"
|
||||
BACKUP_INCLUDE_IPSW="${BACKUP_INCLUDE_IPSW:-0}"
|
||||
|
||||
# --- Parse args ---
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--name) NAME="$2"; shift 2 ;;
|
||||
--include-ipsw) BACKUP_INCLUDE_IPSW=1; shift ;;
|
||||
-h|--help)
|
||||
echo "Usage: $0 --name <name> [--include-ipsw]"
|
||||
exit 0
|
||||
;;
|
||||
*) echo "Unknown option: $1"; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ -z "${NAME}" ]]; then
|
||||
echo "ERROR: NAME is required."
|
||||
echo " Usage: make vm_backup NAME=ios17"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Reject names with slashes or dots to keep the backups dir clean
|
||||
if [[ "${NAME}" == */* || "${NAME}" == .* ]]; then
|
||||
echo "ERROR: NAME must be a simple identifier (no slashes or leading dots)."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- Validate source ---
|
||||
if [[ ! -d "${VM_DIR}" ]]; then
|
||||
echo "ERROR: VM directory not found: ${VM_DIR}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -f "${VM_DIR}/config.plist" ]]; then
|
||||
echo "ERROR: ${VM_DIR}/config.plist not found — is this a valid VM directory?"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- Check for running VM ---
|
||||
if pgrep -f "vphone-cli.*--config.*${VM_DIR}" >/dev/null 2>&1; then
|
||||
echo "WARNING: vphone-cli appears to be running against ${VM_DIR}."
|
||||
echo " Backing up a live VM may produce an inconsistent snapshot."
|
||||
printf "Continue anyway? [y/N] "
|
||||
read -r answer
|
||||
[[ "${answer}" =~ ^[Yy]$ ]] || exit 1
|
||||
fi
|
||||
|
||||
DEST="${BACKUPS_DIR}/${NAME}"
|
||||
|
||||
echo "=== vphone vm_backup ==="
|
||||
echo "Name : ${NAME}"
|
||||
echo "Source : ${VM_DIR}/"
|
||||
echo "Dest : ${DEST}/"
|
||||
src_size="$(du -sh "${VM_DIR}" 2>/dev/null | cut -f1)"
|
||||
echo "Size : ${src_size} (on disk)"
|
||||
|
||||
RSYNC_EXCLUDES=()
|
||||
if [[ "${BACKUP_INCLUDE_IPSW}" != "1" ]]; then
|
||||
RSYNC_EXCLUDES+=(--exclude '*_Restore*/')
|
||||
echo "IPSW : excluded (use BACKUP_INCLUDE_IPSW=1 to include)"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# --- Sync ---
|
||||
mkdir -p "${DEST}"
|
||||
|
||||
rsync -aH --sparse --progress --delete \
|
||||
"${RSYNC_EXCLUDES[@]}" \
|
||||
"${VM_DIR}/" "${DEST}/"
|
||||
|
||||
# Tag the active VM with this name
|
||||
echo "${NAME}" > "${VM_DIR}/.vm_name"
|
||||
|
||||
echo ""
|
||||
echo "=== Saved as '${NAME}' ==="
|
||||
backup_size="$(du -sh "${DEST}" 2>/dev/null | cut -f1)"
|
||||
echo "Backup size : ${backup_size}"
|
||||
echo ""
|
||||
echo "To restore : make vm_restore NAME=${NAME}"
|
||||
echo "To switch : make vm_switch NAME=${NAME}"
|
||||
echo "List all : make vm_list"
|
||||
102
scripts/vm_restore.sh
Executable file
102
scripts/vm_restore.sh
Executable file
@@ -0,0 +1,102 @@
|
||||
#!/bin/zsh
|
||||
# vm_restore.sh — Restore a named backup into the active VM directory.
|
||||
#
|
||||
# Usage:
|
||||
# make vm_restore NAME=ios17
|
||||
# make vm_restore NAME=ios17 FORCE=1
|
||||
set -euo pipefail
|
||||
|
||||
VM_DIR="${VM_DIR:-vm}"
|
||||
BACKUPS_DIR="${BACKUPS_DIR:-vm.backups}"
|
||||
NAME="${NAME:-}"
|
||||
FORCE="${FORCE:-0}"
|
||||
|
||||
# --- Parse args ---
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--name) NAME="$2"; shift 2 ;;
|
||||
--force) FORCE=1; shift ;;
|
||||
-h|--help)
|
||||
echo "Usage: $0 --name <name> [--force]"
|
||||
exit 0
|
||||
;;
|
||||
*) echo "Unknown option: $1"; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ -z "${NAME}" ]]; then
|
||||
echo "ERROR: NAME is required."
|
||||
echo " Usage: make vm_restore NAME=ios17"
|
||||
echo ""
|
||||
echo "Available backups:"
|
||||
if [[ -d "${BACKUPS_DIR}" ]]; then
|
||||
for d in "${BACKUPS_DIR}"/*/; do
|
||||
[[ -f "${d}config.plist" ]] && echo " - $(basename "${d}")"
|
||||
done
|
||||
else
|
||||
echo " (none)"
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SRC="${BACKUPS_DIR}/${NAME}"
|
||||
|
||||
# --- Validate backup ---
|
||||
if [[ ! -d "${SRC}" ]]; then
|
||||
echo "ERROR: Backup '${NAME}' not found at ${SRC}/"
|
||||
echo ""
|
||||
echo "Available backups:"
|
||||
if [[ -d "${BACKUPS_DIR}" ]]; then
|
||||
for d in "${BACKUPS_DIR}"/*/; do
|
||||
[[ -f "${d}config.plist" ]] && echo " - $(basename "${d}")"
|
||||
done
|
||||
else
|
||||
echo " (none)"
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -f "${SRC}/config.plist" ]]; then
|
||||
echo "ERROR: ${SRC}/config.plist not found — backup appears invalid."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- Check for running VM ---
|
||||
if pgrep -f "vphone-cli.*--config.*${VM_DIR}" >/dev/null 2>&1; then
|
||||
echo "ERROR: vphone-cli appears to be running against ${VM_DIR}."
|
||||
echo " Stop the VM before restoring."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- Confirm overwrite ---
|
||||
if [[ -d "${VM_DIR}" && -f "${VM_DIR}/Disk.img" && "${FORCE}" != "1" ]]; then
|
||||
current=""
|
||||
[[ -f "${VM_DIR}/.vm_name" ]] && current="$(< "${VM_DIR}/.vm_name")"
|
||||
echo "WARNING: ${VM_DIR}/ already exists${current:+ (current: '${current}')}."
|
||||
echo " This will overwrite it with backup '${NAME}'."
|
||||
echo " Back up first with: make vm_backup NAME=<name>"
|
||||
printf "Continue? [y/N] "
|
||||
read -r answer
|
||||
[[ "${answer}" =~ ^[Yy]$ ]] || exit 1
|
||||
fi
|
||||
|
||||
echo "=== vphone vm_restore ==="
|
||||
echo "Name : ${NAME}"
|
||||
echo "Source : ${SRC}/"
|
||||
echo "Dest : ${VM_DIR}/"
|
||||
backup_size="$(du -sh "${SRC}" 2>/dev/null | cut -f1)"
|
||||
echo "Size : ${backup_size} (on disk)"
|
||||
echo ""
|
||||
|
||||
# --- Sync ---
|
||||
mkdir -p "${VM_DIR}"
|
||||
|
||||
rsync -aH --sparse --progress --delete \
|
||||
"${SRC}/" "${VM_DIR}/"
|
||||
|
||||
# Tag the active VM
|
||||
echo "${NAME}" > "${VM_DIR}/.vm_name"
|
||||
|
||||
echo ""
|
||||
echo "=== Restored '${NAME}' ==="
|
||||
echo "Next: make boot"
|
||||
118
scripts/vm_switch.sh
Executable file
118
scripts/vm_switch.sh
Executable file
@@ -0,0 +1,118 @@
|
||||
#!/bin/zsh
|
||||
# vm_switch.sh — Switch the active VM to a different named backup.
|
||||
#
|
||||
# Saves the current VM under its name (from vm/.vm_name), then restores
|
||||
# the target backup. If the current VM has no name yet, prompts for one.
|
||||
#
|
||||
# Usage:
|
||||
# make vm_switch NAME=ios18
|
||||
set -euo pipefail
|
||||
|
||||
VM_DIR="${VM_DIR:-vm}"
|
||||
BACKUPS_DIR="${BACKUPS_DIR:-vm.backups}"
|
||||
NAME="${NAME:-}"
|
||||
BACKUP_INCLUDE_IPSW="${BACKUP_INCLUDE_IPSW:-0}"
|
||||
|
||||
# --- Parse args ---
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--name) NAME="$2"; shift 2 ;;
|
||||
--include-ipsw) BACKUP_INCLUDE_IPSW=1; shift ;;
|
||||
-h|--help)
|
||||
echo "Usage: $0 --name <target> [--include-ipsw]"
|
||||
exit 0
|
||||
;;
|
||||
*) echo "Unknown option: $1"; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ -z "${NAME}" ]]; then
|
||||
echo "ERROR: NAME is required (the backup to switch to)."
|
||||
echo " Usage: make vm_switch NAME=ios18"
|
||||
echo ""
|
||||
echo "Available backups:"
|
||||
if [[ -d "${BACKUPS_DIR}" ]]; then
|
||||
for d in "${BACKUPS_DIR}"/*/; do
|
||||
[[ -f "${d}config.plist" ]] && echo " - $(basename "${d}")"
|
||||
done
|
||||
else
|
||||
echo " (none)"
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TARGET="${BACKUPS_DIR}/${NAME}"
|
||||
|
||||
if [[ ! -d "${TARGET}" || ! -f "${TARGET}/config.plist" ]]; then
|
||||
echo "ERROR: Backup '${NAME}' not found."
|
||||
echo ""
|
||||
echo "Available backups:"
|
||||
if [[ -d "${BACKUPS_DIR}" ]]; then
|
||||
for d in "${BACKUPS_DIR}"/*/; do
|
||||
[[ -f "${d}config.plist" ]] && echo " - $(basename "${d}")"
|
||||
done
|
||||
else
|
||||
echo " (none)"
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- Check for running VM ---
|
||||
if pgrep -f "vphone-cli.*--config.*${VM_DIR}" >/dev/null 2>&1; then
|
||||
echo "ERROR: vphone-cli appears to be running against ${VM_DIR}."
|
||||
echo " Stop the VM before switching."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- Determine current VM name ---
|
||||
CURRENT=""
|
||||
if [[ -d "${VM_DIR}" && -f "${VM_DIR}/config.plist" ]]; then
|
||||
if [[ -f "${VM_DIR}/.vm_name" ]]; then
|
||||
CURRENT="$(< "${VM_DIR}/.vm_name")"
|
||||
fi
|
||||
|
||||
if [[ -z "${CURRENT}" ]]; then
|
||||
echo "Current VM has no name. Give it one to save before switching."
|
||||
printf "Name for current VM: "
|
||||
read -r CURRENT
|
||||
if [[ -z "${CURRENT}" ]]; then
|
||||
echo "ERROR: Cannot switch without saving the current VM."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "${CURRENT}" == "${NAME}" ]]; then
|
||||
echo "'${NAME}' is already the active VM."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# --- Save current ---
|
||||
echo "=== Saving current VM as '${CURRENT}' ==="
|
||||
CURRENT_DEST="${BACKUPS_DIR}/${CURRENT}"
|
||||
mkdir -p "${CURRENT_DEST}"
|
||||
|
||||
RSYNC_EXCLUDES=()
|
||||
if [[ "${BACKUP_INCLUDE_IPSW}" != "1" ]]; then
|
||||
RSYNC_EXCLUDES+=(--exclude '*_Restore*/')
|
||||
fi
|
||||
|
||||
rsync -aH --sparse --progress --delete \
|
||||
"${RSYNC_EXCLUDES[@]}" \
|
||||
"${VM_DIR}/" "${CURRENT_DEST}/"
|
||||
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# --- Restore target ---
|
||||
echo "=== Restoring '${NAME}' ==="
|
||||
|
||||
mkdir -p "${VM_DIR}"
|
||||
|
||||
rsync -aH --sparse --progress --delete \
|
||||
"${TARGET}/" "${VM_DIR}/"
|
||||
|
||||
echo "${NAME}" > "${VM_DIR}/.vm_name"
|
||||
|
||||
echo ""
|
||||
echo "=== Switched: ${CURRENT:+${CURRENT} → }${NAME} ==="
|
||||
echo "Next: make boot"
|
||||
Reference in New Issue
Block a user