Refine backup validation and manifest details
This commit is contained in:
@@ -355,6 +355,7 @@ if [[ "$LND_AVAILABLE" -eq 1 ]]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
ESTIMATED_BYTES=$(( ETC_NIXOS_BYTES + HOME_BYTES + SECRETS_BYTES + VAR_LIB_BYTES + LND_BYTES ))
|
ESTIMATED_BYTES=$(( ETC_NIXOS_BYTES + HOME_BYTES + SECRETS_BYTES + VAR_LIB_BYTES + LND_BYTES ))
|
||||||
|
# Require 20% growth headroom plus an additional fixed 1 GiB safety margin.
|
||||||
REQUIRED_BYTES=$(( ESTIMATED_BYTES + (ESTIMATED_BYTES / 5) + SAFETY_MARGIN_BYTES ))
|
REQUIRED_BYTES=$(( ESTIMATED_BYTES + (ESTIMATED_BYTES / 5) + SAFETY_MARGIN_BYTES ))
|
||||||
|
|
||||||
FREE_BYTES=$(df -B1 --output=avail "$TARGET" | tail -1 | tr -d ' ')
|
FREE_BYTES=$(df -B1 --output=avail "$TARGET" | tail -1 | tr -d ' ')
|
||||||
@@ -716,8 +717,6 @@ CHECKSUM_FILE="$BACKUP_DIR/SHA256SUMS.txt"
|
|||||||
find "$BACKUP_DIR" -mindepth 1 -maxdepth 2 -type f | sort
|
find "$BACKUP_DIR" -mindepth 1 -maxdepth 2 -type f | sort
|
||||||
} > "$MANIFEST_FILE"
|
} > "$MANIFEST_FILE"
|
||||||
|
|
||||||
ARCHIVE_FILES+=("BACKUP_MANIFEST.txt")
|
|
||||||
|
|
||||||
# ── Generate checksums for all backup artifacts ─────────────────
|
# ── Generate checksums for all backup artifacts ─────────────────
|
||||||
|
|
||||||
log "Generating SHA-256 checksums …"
|
log "Generating SHA-256 checksums …"
|
||||||
|
|||||||
@@ -1493,6 +1493,41 @@ def _is_internal_mount(mnt: str) -> bool:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def _is_supported_backup_fstype(path: str, fstype: str) -> bool:
|
||||||
|
"""Return whether the target filesystem type is supported for manual backup."""
|
||||||
|
fstype = (fstype or "").lower()
|
||||||
|
if fstype == "exfat":
|
||||||
|
return True
|
||||||
|
if fstype != "fuseblk":
|
||||||
|
return False
|
||||||
|
|
||||||
|
src_dev = ""
|
||||||
|
try:
|
||||||
|
result = subprocess.run(
|
||||||
|
["findmnt", "-n", "-o", "SOURCE", "-T", path],
|
||||||
|
capture_output=True, text=True, timeout=5,
|
||||||
|
)
|
||||||
|
if result.returncode == 0:
|
||||||
|
src_dev = result.stdout.strip()
|
||||||
|
except Exception:
|
||||||
|
src_dev = ""
|
||||||
|
|
||||||
|
if not src_dev:
|
||||||
|
return False
|
||||||
|
|
||||||
|
for cmd in (
|
||||||
|
["lsblk", "-no", "FSTYPE", src_dev],
|
||||||
|
["blkid", "-o", "value", "-s", "TYPE", src_dev],
|
||||||
|
):
|
||||||
|
try:
|
||||||
|
result = subprocess.run(cmd, capture_output=True, text=True, timeout=5)
|
||||||
|
if result.returncode == 0 and result.stdout.strip().lower() in {"exfat", "fuseblk"}:
|
||||||
|
return True
|
||||||
|
except Exception:
|
||||||
|
continue
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def _detect_external_drives() -> list[dict]:
|
def _detect_external_drives() -> list[dict]:
|
||||||
"""Scan for mounted external USB drives.
|
"""Scan for mounted external USB drives.
|
||||||
|
|
||||||
@@ -3746,7 +3781,7 @@ async def api_backup_run(target: str = ""):
|
|||||||
|
|
||||||
selected_target = selected.get("path", "")
|
selected_target = selected.get("path", "")
|
||||||
selected_fstype = (selected.get("fstype") or "").lower()
|
selected_fstype = (selected.get("fstype") or "").lower()
|
||||||
if selected_fstype and selected_fstype not in {"exfat", "fuseblk"}:
|
if selected_fstype and not _is_supported_backup_fstype(selected_target, selected_fstype):
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=400,
|
status_code=400,
|
||||||
detail=f"Selected drive filesystem '{selected_fstype}' is not supported for manual backup.",
|
detail=f"Selected drive filesystem '{selected_fstype}' is not supported for manual backup.",
|
||||||
|
|||||||
Reference in New Issue
Block a user