docs: add remote backup design spec and implementation plan
This commit is contained in:
246
docs/superpowers/plans/2026-05-09-remote-backup.md
Normal file
246
docs/superpowers/plans/2026-05-09-remote-backup.md
Normal file
@@ -0,0 +1,246 @@
|
|||||||
|
# Remote Backup (WebDAV & SMB) Implementation Plan
|
||||||
|
|
||||||
|
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||||
|
|
||||||
|
**Goal:** Add WebDAV upload and SMB mount backup support to the backup script using built-in busybox tools.
|
||||||
|
|
||||||
|
**Architecture:** Four config variables in `backup_settings.conf` control remote backup. Five new functions in `tools/tools.sh` handle SMB mount/unmount and WebDAV upload. A single hook in `backup_path()` triggers remote setup. The existing EXIT trap is extended to handle remote cleanup.
|
||||||
|
|
||||||
|
**Tech Stack:** Shell script (Android mksh compatible), busybox (wget, mount, umount)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## File Structure
|
||||||
|
|
||||||
|
| File | Action | Responsibility |
|
||||||
|
|------|--------|---------------|
|
||||||
|
| `backup_settings.conf` | Append | Remote backup configuration |
|
||||||
|
| `tools/tools.sh` | Modify | Remote backup functions + hook + trap extension |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 1: Add remote config to backup_settings.conf
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `backup_settings.conf`
|
||||||
|
|
||||||
|
- [ ] **Step 1: Append remote backup configuration**
|
||||||
|
|
||||||
|
Append after line 123 (`rgb_c=177`), before the trailing newline at line 124:
|
||||||
|
|
||||||
|
```conf
|
||||||
|
|
||||||
|
#遠程備份類型 (留空不啟用)
|
||||||
|
#webdav 或 smb
|
||||||
|
remote_type=
|
||||||
|
|
||||||
|
#遠程地址
|
||||||
|
#WebDAV例: http://192.168.1.100:8080/dav/
|
||||||
|
#SMB例: //192.168.1.100/backup
|
||||||
|
remote_url=
|
||||||
|
|
||||||
|
#遠程認證用戶名
|
||||||
|
remote_user=
|
||||||
|
|
||||||
|
#遠程認證密碼
|
||||||
|
remote_pass=
|
||||||
|
```
|
||||||
|
|
||||||
|
Edit command: Use the Edit tool to append these lines after `rgb_c=177`.
|
||||||
|
|
||||||
|
- [ ] **Step 2: Verify config file**
|
||||||
|
|
||||||
|
Run: Read `backup_settings.conf` lines 120-140 to confirm the config lines are present.
|
||||||
|
|
||||||
|
- [ ] **Step 3: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add backup_settings.conf
|
||||||
|
git commit -m "feat: add remote backup config (remote_type, remote_url, remote_user, remote_pass)"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 2: Add remote backup functions to tools.sh
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `tools/tools.sh` (insert after line 465, before `Show_boottime` at line 466)
|
||||||
|
|
||||||
|
- [ ] **Step 1: Insert remote functions**
|
||||||
|
|
||||||
|
Insert after line 465 (`kill_Serve` call) and before line 466 (`Show_boottime()`):
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# -------- 遠程備份功能 --------
|
||||||
|
mount_smb() {
|
||||||
|
local mnt="$TMPDIR/smb_mount"
|
||||||
|
mkdir -p "$mnt"
|
||||||
|
if busybox mount -t cifs "$remote_url" "$mnt" -o "username=$remote_user,password=$remote_pass,iocharset=utf8,vers=2.0" 2>/dev/null; then
|
||||||
|
SMB_MOUNT="$mnt"
|
||||||
|
[[ $(mount | grep "$mnt") != "" ]] || { echoRgb "SMB掛載失敗: $remote_url" "0"; return 1; }
|
||||||
|
echoRgb "SMB已掛載: $remote_url -> $mnt" "1"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
echoRgb "SMB掛載失敗,回退本地備份" "0"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
umount_smb() {
|
||||||
|
[[ -n $SMB_MOUNT ]] && {
|
||||||
|
busybox umount -l "$SMB_MOUNT" 2>/dev/null
|
||||||
|
rm -rf "$SMB_MOUNT"
|
||||||
|
unset SMB_MOUNT
|
||||||
|
echoRgb "SMB已卸載" "2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
upload_webdav() {
|
||||||
|
local base_url="${remote_url%/}"
|
||||||
|
local auth=$(echo -n "$remote_user:$remote_pass" | busybox base64)
|
||||||
|
local failed=0
|
||||||
|
local list_file="$TMPDIR/.wdav_list"
|
||||||
|
find "$Backup" -type f > "$list_file"
|
||||||
|
while read -r f; do
|
||||||
|
[[ -z $f ]] && continue
|
||||||
|
local rel="${f#$Backup/}"
|
||||||
|
echoRgb "上傳: $rel" "2"
|
||||||
|
if busybox wget -q --method PUT --body-file="$f" --header "Authorization: Basic $auth" "$base_url/$rel" 2>/dev/null; then
|
||||||
|
rm -f "$f"
|
||||||
|
else
|
||||||
|
failed=1
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done < "$list_file"
|
||||||
|
rm -f "$list_file"
|
||||||
|
if [[ $failed -eq 0 ]]; then
|
||||||
|
echoRgb "WebDAV上傳完成" "1"
|
||||||
|
else
|
||||||
|
echoRgb "WebDAV上傳失敗,本地檔案已保留" "0"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
remote_setup() {
|
||||||
|
[[ -z $remote_type ]] && return
|
||||||
|
|
||||||
|
case $remote_type in
|
||||||
|
smb)
|
||||||
|
mount_smb || return
|
||||||
|
Backup="$SMB_MOUNT/Backup_${Compression_method}_$user"
|
||||||
|
mkdir -p "$Backup"
|
||||||
|
Backup_path="${Backup%/*}"
|
||||||
|
Output_path=""
|
||||||
|
echoRgb "遠程備份目錄: $Backup" "3"
|
||||||
|
;;
|
||||||
|
webdav)
|
||||||
|
echoRgb "WebDAV模式: 備份完成後將自動上傳" "3"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
remote_cleanup() {
|
||||||
|
case $remote_type in
|
||||||
|
smb) umount_smb ;;
|
||||||
|
webdav) upload_webdav ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 2: Verify insertion**
|
||||||
|
|
||||||
|
Run: Read `tools/tools.sh` lines 464-550 to confirm functions are inserted correctly and `Show_boottime()` follows.
|
||||||
|
|
||||||
|
- [ ] **Step 3: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add tools/tools.sh
|
||||||
|
git commit -m "feat: add remote backup functions (mount_smb, umount_smb, upload_webdav, remote_setup, remote_cleanup)"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 3: Wire hook and trap
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `tools/tools.sh` (line 462 and line 991-993)
|
||||||
|
|
||||||
|
- [ ] **Step 1: Modify EXIT trap in kill_Serve**
|
||||||
|
|
||||||
|
Change line 462 from:
|
||||||
|
```sh
|
||||||
|
trap "rm -rf '$LOCK_DIR'" EXIT
|
||||||
|
```
|
||||||
|
to:
|
||||||
|
```sh
|
||||||
|
trap "rm -rf '$LOCK_DIR'; remote_cleanup" EXIT
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 2: Add remote_setup call at end of backup_path()**
|
||||||
|
|
||||||
|
Change line 991-993 from:
|
||||||
|
```sh
|
||||||
|
echoRgb "$hx備份資料夾所使用分區統計如下↓\n -$(df -h "${Backup%/*}" | sed -n 's|% /.*|%|p' | awk '{print $(NF-3),$(NF-2),$(NF-1),$(NF)}' | awk 'END{print "總共:"$1"已用:"$2"剩餘:"$3"使用率:"$4}')檔案系統:$(df -T "$Backup_path" | sed -n 's|% /.*|%|p' | awk '{print $(NF-4)}')\n -備份目錄輸出位置↓\n -$Backup"
|
||||||
|
echoRgb "$outshow" "2"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
to:
|
||||||
|
```sh
|
||||||
|
echoRgb "$hx備份資料夾所使用分區統計如下↓\n -$(df -h "${Backup%/*}" | sed -n 's|% /.*|%|p' | awk '{print $(NF-3),$(NF-2),$(NF-1),$(NF)}' | awk 'END{print "總共:"$1"已用:"$2"剩餘:"$3"使用率:"$4}')檔案系統:$(df -T "$Backup_path" | sed -n 's|% /.*|%|p' | awk '{print $(NF-4)}')\n -備份目錄輸出位置↓\n -$Backup"
|
||||||
|
echoRgb "$outshow" "2"
|
||||||
|
remote_setup
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 3: Verify EXIT trap**
|
||||||
|
|
||||||
|
Run: Read `tools/tools.sh` line 462 to confirm the trap includes `remote_cleanup`.
|
||||||
|
|
||||||
|
- [ ] **Step 4: Verify hook**
|
||||||
|
|
||||||
|
Run: Read `tools/tools.sh` lines 989-994 to confirm `remote_setup` is inside `backup_path()` before the closing `}`.
|
||||||
|
|
||||||
|
- [ ] **Step 5: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add tools/tools.sh
|
||||||
|
git commit -m "feat: wire remote backup hook and EXIT trap"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 4: Verify changes
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Check: `tools/tools.sh`, `backup_settings.conf`
|
||||||
|
|
||||||
|
- [ ] **Step 1: Verify git diff**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git diff master
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: ~80 lines added across 2 files:
|
||||||
|
- `backup_settings.conf`: +9 lines (remote config)
|
||||||
|
- `tools/tools.sh`: +~70 lines (functions, trap modification, hook), 1 line modified (trap), 1 line added (hook call)
|
||||||
|
|
||||||
|
- [ ] **Step 2: Verify no syntax errors in shell script**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash -n tools/tools.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Ignore "not found" warnings for Android-specific tools — we're only checking syntax.
|
||||||
|
|
||||||
|
- [ ] **Step 3: Verify function names don't collide**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
Select-String -Pattern "^(mount_smb|umount_smb|upload_webdav|remote_setup|remote_cleanup)\b" -Path tools/tools.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected: Each function name appears once (definition only, not duplicated).
|
||||||
|
|
||||||
|
- [ ] **Step 4: Commit any fixes if needed**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add -A && git commit -m "fix: address verification issues"
|
||||||
|
```
|
||||||
136
docs/superpowers/specs/2026-05-09-remote-backup-design.md
Normal file
136
docs/superpowers/specs/2026-05-09-remote-backup-design.md
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
# Remote Backup (WebDAV & SMB) 设计文档
|
||||||
|
|
||||||
|
**日期:** 2026-05-09
|
||||||
|
**目标:** 在不涉及大范围改动的前提下,为脚本增加备份到远程 WebDAV 和 SMB 的功能。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 需求
|
||||||
|
|
||||||
|
- 支持直接备份到远程 WebDAV 和 SMB 设备
|
||||||
|
- 使用脚本内置 busybox,不依赖额外工具
|
||||||
|
- 配置通过 `backup_settings.conf`
|
||||||
|
- 最小化对现有代码的改动
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 架构
|
||||||
|
|
||||||
|
### 配置
|
||||||
|
|
||||||
|
在 `backup_settings.conf` 末尾追加 4 个配置项:
|
||||||
|
|
||||||
|
```conf
|
||||||
|
#远程备份类型 (留空不启用)
|
||||||
|
#webdav 或 smb
|
||||||
|
remote_type=
|
||||||
|
|
||||||
|
#远程地址
|
||||||
|
#WebDAV例: http://192.168.1.100:8080/dav/
|
||||||
|
#SMB例: //192.168.1.100/backup
|
||||||
|
remote_url=
|
||||||
|
|
||||||
|
#远程认证用户名
|
||||||
|
remote_user=
|
||||||
|
|
||||||
|
#远程认证密码
|
||||||
|
remote_pass=
|
||||||
|
```
|
||||||
|
|
||||||
|
### 新增函数(tools/tools.sh)
|
||||||
|
|
||||||
|
所有函数定义在 `tools/tools.sh` 中,靠近 `kill_Serve()` 之后的位置(~line 465)。
|
||||||
|
|
||||||
|
| 函数 | 行数 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| `mount_smb()` | ~10 | busybox `mount -t cifs` 挂载 SMB 到 `$TMPDIR/smb_mount` |
|
||||||
|
| `umount_smb()` | ~5 | 安全卸载 SMB 挂载点 |
|
||||||
|
| `upload_webdav()` | ~20 | 遍历备份目录,用 busybox `wget --method PUT` 逐个上传 |
|
||||||
|
| `remote_setup()` | ~25 | 入口函数:SMB 挂载后设置 Output_path;WebDAV 注册 trap |
|
||||||
|
| `remote_cleanup()` | ~15 | SMB 卸载 / WebDAV 上传+清理本地文件 |
|
||||||
|
|
||||||
|
### Hook 点
|
||||||
|
|
||||||
|
在 `backup_path()` 调用之后(line 991 附近)插入一行:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
remote_setup
|
||||||
|
```
|
||||||
|
|
||||||
|
### 流程
|
||||||
|
|
||||||
|
```
|
||||||
|
backup_path() # 确定本地备份路径 $Backup
|
||||||
|
↓
|
||||||
|
remote_setup() # 如启用远程,挂载 SMB 或准备 WebDAV uploader
|
||||||
|
↓
|
||||||
|
[SMB] [WebDAV]
|
||||||
|
mount_smb() 正常本地备份
|
||||||
|
$Backup → mount ↓
|
||||||
|
正常备份 upload_webdav() (at EXIT)
|
||||||
|
↓ rm -rf 本地副本
|
||||||
|
umount_smb()
|
||||||
|
```
|
||||||
|
|
||||||
|
### SMB 实现细节
|
||||||
|
|
||||||
|
```sh
|
||||||
|
mount_smb() {
|
||||||
|
local mnt="$TMPDIR/smb_mount"
|
||||||
|
mkdir -p "$mnt"
|
||||||
|
busybox mount -t cifs "$remote_url" "$mnt" -o "username=$remote_user,password=$remote_pass,iocharset=utf8"
|
||||||
|
# 若 busybox mount 不支持 cifs,尝试系统 mount
|
||||||
|
# 失败则返回非0,remote_setup 回退到本地备份
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
挂载成功后,`remote_setup()` 将 `$Backup` 覆盖为 `$mnt/Backup_${Compression_method}_$user`,后续备份流程无需修改。
|
||||||
|
|
||||||
|
### WebDAV 实现细节
|
||||||
|
|
||||||
|
```sh
|
||||||
|
upload_webdav() {
|
||||||
|
local base_url="${remote_url%/}"
|
||||||
|
# 创建远程目录 (MKCOL)
|
||||||
|
busybox wget -q --method MKCOL --header "Authorization: ..." "$base_url/..." 2>/dev/null
|
||||||
|
# 遍历上传
|
||||||
|
find "$Backup" -type f | while read f; do
|
||||||
|
busybox wget -q --method PUT --body-file="$f" --header "Authorization: ..." "$base_url/..."
|
||||||
|
# 上传成功才删除本地文件
|
||||||
|
done
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
备份先写到本地(正常流程),EXIT 时 `remote_cleanup()` 触发上传,成功后删除本地副本。
|
||||||
|
|
||||||
|
### 错误处理
|
||||||
|
|
||||||
|
- SMB 挂载失败:回退到本地备份(echo 警告,继续执行)
|
||||||
|
- WebDAV 上传失败:保留本地文件不删除(保留数据,用户手动排查)
|
||||||
|
- SMB 连接断开:trap EXIT 确保 `umount_smb()` 被调用
|
||||||
|
- 网络异常:wget 自带超时,不会永久阻塞
|
||||||
|
|
||||||
|
### 恢复支持(后续迭代)
|
||||||
|
|
||||||
|
本次仅实现备份到远程。恢复从远程可在后续 PR 中补充,方向是对称实现:
|
||||||
|
- SMB:挂载后从挂载点恢复
|
||||||
|
- WebDAV:wget 下载到临时目录后恢复
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 改动范围
|
||||||
|
|
||||||
|
| 文件 | 改动 |
|
||||||
|
|------|------|
|
||||||
|
| `backup_settings.conf` | +9 行配置 |
|
||||||
|
| `tools/tools.sh` | +75 行(5 个函数 + 1 个 hook 调用) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 测试要点
|
||||||
|
|
||||||
|
1. SMB 挂载成功 → 备份文件出现在远程共享目录
|
||||||
|
2. SMB 挂载失败 → 回退到本地备份,有警告提示
|
||||||
|
3. WebDAV 上传成功 → 远程有备份文件,本地副本已清理
|
||||||
|
4. WebDAV 上传失败 → 本地文件保留,有错误提示
|
||||||
|
5. EXIT 时 SMB 挂载点被正确卸载(无残留)
|
||||||
Reference in New Issue
Block a user