From e00d5a933ccf6e06aeec48dd5a80dd6126ac656a Mon Sep 17 00:00:00 2001 From: Houssem Chergui Date: Sat, 16 May 2026 14:04:20 +0100 Subject: [PATCH] Fix VIRTNBD_FALSE_SUCCESS false-positive on Windows VMs with BitLocker The post-backup ERROR-line scan in perform_backup() used a case- insensitive substring match (grep -qi "ERROR"), which fired on the word "ERROR" appearing inside INFO/WARN payloads. On Windows VMs the QEMU guest agent surfaces BitLocker status text that contains the word during normal operation, marking otherwise-successful backups as failed and triggering retries and spurious alert noise. The check is now anchored to the timestamped severity prefix (^[YYYY-MM-DD HH:MM:SS] ERROR ) so only real ERROR-level records trigger the guard. ANSI colour escapes from virtnbdbackup are stripped before the anchor match so coloured output still matches. Same fix applied to the diagnostic snippet extraction. --- CHANGELOG.md | 6 ++++++ vmbackup.sh | 17 +++++++++++------ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5341da1..cb9413c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,12 @@ All notable changes to [vmbackup](https://github.com/doutsis/vmbackup) will be d Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). Versions follow [Semantic Versioning](https://semver.org/). +## [Unreleased] + +### Fixed + +- **`VIRTNBD_FALSE_SUCCESS` false-positive on Windows VMs with BitLocker** — The post-backup ERROR-line scan in `perform_backup()` used a case-insensitive substring match (`grep -qi "ERROR"`), which fired on the word "ERROR" appearing inside INFO/WARN payloads. On Windows VMs the QEMU guest agent surfaces BitLocker status text containing the word during normal operation, marking otherwise-successful backups as failed and triggering retries / spurious alert noise. The check is now anchored to the timestamped severity prefix (`^[YYYY-MM-DD HH:MM:SS] ERROR `) so only real `ERROR`-level records trigger the guard, with ANSI colour escapes stripped first so coloured output still matches. Same fix applied to the diagnostic snippet extraction. + ## [0.5.6] - 2026-04-26 ### Changed diff --git a/vmbackup.sh b/vmbackup.sh index 4bc78c3..eaba38e 100755 --- a/vmbackup.sh +++ b/vmbackup.sh @@ -3587,13 +3587,18 @@ perform_backup() { pkill -P $monitor_pid 2>/dev/null || true kill $monitor_pid 2>/dev/null || true - # virtnbdbackup sometimes exits 0 despite logging ERROR lines (e.g., - # "target directory already contains full or copy backup", bitmap - # conflicts, extent read failures). Scan the captured log for any - # ERROR line and treat it as a backup failure. - if [[ -f "$backup_log" ]] && grep -qi "ERROR" "$backup_log" 2>/dev/null; then + # virtnbdbackup sometimes exits 0 despite logging ERROR lines. Anchor + # the match to the timestamped severity prefix so the word "ERROR" + # appearing inside INFO/WARN payloads (e.g. Windows guest-agent + # BitLocker status) doesn't produce a false failure. Strip ANSI + # colour escapes first so coloured output still matches. + if [[ -f "$backup_log" ]] && \ + sed -E 's/\x1b\[[0-9;]*m//g' "$backup_log" | \ + grep -qE '^\[[0-9-]{10} [0-9:]{8}\] ERROR ' 2>/dev/null; then local error_lines - error_lines=$(grep -i "ERROR" "$backup_log" 2>/dev/null | tail -3 | tr '\n' ' ' | cut -c1-200) + error_lines=$(sed -E 's/\x1b\[[0-9;]*m//g' "$backup_log" | \ + grep -E '^\[[0-9-]{10} [0-9:]{8}\] ERROR ' 2>/dev/null | \ + tail -3 | tr '\n' ' ' | cut -c1-200) log_error "vmbackup.sh" "perform_backup" \ "virtnbdbackup exited 0 but logged ERROR(s) for VM $vm_name: $error_lines" set_backup_error "VIRTNBD_FALSE_SUCCESS" \