diff --git a/playbook/blancco-preferences.xml b/playbook/blancco-preferences.xml
index ca8991c..6e6edd5 100644
--- a/playbook/blancco-preferences.xml
+++ b/playbook/blancco-preferences.xml
@@ -1,49 +1,42 @@
-
+
7
- 15
- 1
+ 20
+ 0
-
-
-
-
- false
-
-
+ qJ4hjOqd1NaMbEPsbmaz+8gZlG1duEXinTXI+Wrsc00=
+
workflow
auto
semi
manual
-
-
- battery
+
+ battery
cpu
memory
motherboard
- battery_discharge
- bios_logo
- cpu_stress
- display
- keyboard
- microphone
- network
- optical_devices
- sound
- pointing_devices
- sim_presence
- speaker
- touchscreen
- usb_ports
- webcam
- wifi
+ battery_discharge
+ bios_logo
+ cpu_stress
+ display
+ keyboard
+ microphone
+ network
+ optical_devices
+ sound
+ pointing_devices
+ sim_presence
+ speaker
+ touchscreen
+ usb_ports
+ webcam
+ wifi
-
us
be
@@ -71,7 +64,6 @@
se
sk
-
en_US
de_DE
@@ -88,119 +80,110 @@
zh_CN
zh_TW
-
-
+
-
-
+
+
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
-
+
-
-
-
- false
+ true
true
false
false
-
-
-
-
-
-
+
+
+
+
+
+
-
false
false
-
+ false
+
peap
tls
- false
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
- 20
- true
-
-
blancco
blancco
-
+
172.16.9.1
blancco-reports
-
+
smb
-
-
-
+
+
+
+
+
+
+
+ k7vMT3SelitU7wIfPSTGZiZa/mNcMlwpPsxGNaBDc2Y1s7VsOBHXEsopfRupMP+shwmLq/sKDIgGR3v9hGrN5A1gmDvvMw/Z+ClZmGIeqhzomR34yUncQA/6GXFq6jc4CNtwXQwKRAvw+stQpE9RYqNvtgFyfmQufOrz75xQyejLXUDmA7KpS6ycdXQxzFKUoqRJOEGlM6I2efjEKkjgKQrvkj8nuRDHw5g5hYXyapKXJhJn7fbwK+AWN+vKx4cceSWVM0wqvofq5BnYj+7hyD5RHphoUI1NqDYnhj2qj8dt3nGKi6EpaXtGJTnXmXplOxbT/PLtZ2afYkxZWRH96negSweOJ4fYkRcJQONe8wGukufSLh/pQcY3NNwkJv7UNh2tC4ogyEKo+E8+n3beImrUWybl6FlUk2lnyQYJFihnnolepze4w5JmPZ2yTEbRi94OUj+bdNEt4ZqRBK2HuDfCI/jzz7h+ytyA2H2+SZWQGjr/oy/RN15a6sgzS5T7Nys+yAbXAH8HSMQm5KUEtLWSSICUpNbRsBOcC+oQhoJnCzWNafj0w5gY/uTNjBm9F0Yd+kjdcO2kqnBF6aeFaLWX6HkTh1DCsMyIJtOr5wZYUmLLtRwgsruhauSbkkQxJA5iy9QsC2Kv+SSACeTLU4WP99Q5MEQIWb+Tjx/S4z6qISgMhxhu4ioteopClaBSizn2oBd/y6gdp7Fz0FK8JSOmPx+pwT3QrDULoK07O5w=
+ eHTwqUlvjRsTYm5ljXTb8uN4hiG6ceE5OIBO0PA+TSMCwmI9qD6co8tmDHCwRdiDdZH2bssDAW40ZPQNfxTdKbDHZ0hunEcQob0xnrr8668L4OkZlWx5V17k8KXB5QgBUd0v1ALnvp9m2SQbsnP6IljTtIL+cZNnfrpmSrvPoGFe8fuoxwMrRE9PZett0DHuYnsnaaP7lD/hAWy8hONsp6MbegS0YA7vZi56cFSrpFnPwjWbNxYREfO3FY6kxxOZoslGARLKLS9//EA0DmOzN4HcXhKhVsiIIbNS1rUEpZi8PsAjS9EKPBMaD2riKlmQYkcw4gIis8Cdj649TsqG5+VESRtXtGCelaGPKSZJaeh7x3Obh6Me+TYQBN5gx4YBUB8Ao11MJR1i5cZj0vdYLPknIsZ9EaFOtRozIo5S37sd7uhgsLPX9pUKJBiDMy+a/CP07rqlKS7pI4+onhInRapU1hwTaBQuO1DxvjhtPXwoPrz0aadmq3jXREhs1YRiJ0bIpZcTA6c9zWYWBSQQ/kfbBB18BSEBZmKfUq42K/8ZDmGuhS/rVIXKLU14/VL9vMqngMfxZ9rBLzTQobXmkt9dKTO9VKxd90P3j3epTQXQsPZ2hwW1rF7NlRA3il2iL94aRAgOGWGe0P9O18VmKEd9uGKWVjXid6vNKBK5m5JHBMoN5n7eXxo9uKQEn8Ex6CKN7vMVvbms25RcUiHUOg==
+ classic.eu-west-1.blancco.cloud
+ 443
+ 20
+ false
+
+
+ false
50
- false
+ true
false
false
- false
+ true
interrupt
false
true
true
10
-
+
- false
false
false
false
@@ -219,36 +202,29 @@
true
true
-
false
67000
-
true
-
false
ntfs
-
false
-
- false
+ true
true
- true
+ false
-
false
- 30
+ 60
-
false
80
@@ -264,28 +240,24 @@
webcam
-
- bios
- bios
+ clurichaun
+ clurichaun
Enterprise Volume Edition
+
Drive Eraser
-
-
-
- 2025-03-10
+ BMP Internet - June 2026
+ 2026-06-22
-
-
- General Electric Company
-
-
-
+
+ GE Aerospace
+
+
+ Non_GEAE_Wired
-
local
@@ -295,11 +267,11 @@
true
standard
- false
+ true
false
false
- 30
+ 86400
false
@@ -309,7 +281,7 @@
5
30
- true
+ false
0
@@ -323,8 +295,8 @@
false
true
- 80
true
+ 80
70
@@ -334,47 +306,23 @@
-
+
+
false
true
xml
+ pdf+xml
0
true
false
-
+
false
-
-
-
- custom_field_1
- GERITM Number
-
-
-
- custom_field_2
- Device Name
-
-
-
- custom_field_3
- Device Serial Number
-
-
-
- custom_field_4
- Version
- EVE_20250310
-
-
-
-
-
true
INTERNETACCESS
@@ -382,34 +330,31 @@
WPA-PSK
0
-
- true
+ false
false
false
false
-
false
false
-
false
false
-
+
+ false
+
false
viewer
-
+
5900
-
+
-
-
-
+
false
@@ -420,6 +365,6 @@
https://cdn.blancco.com/products/drive_eraser/download/ota/drive_eraser.json
+
-
diff --git a/scripts/prepare-boot-tools.sh b/scripts/prepare-boot-tools.sh
index 7b499f3..557aaef 100755
--- a/scripts/prepare-boot-tools.sh
+++ b/scripts/prepare-boot-tools.sh
@@ -16,7 +16,7 @@
set -euo pipefail
REPO_ROOT="$(cd "$(dirname "$0")"/.. && pwd)"
-OUT_DIR="$REPO_ROOT/boot-tools"
+OUT_DIR="${OUT_DIR:-$REPO_ROOT/boot-tools}"
BLANCCO_ISO="${1:-}"
# Auto-detect Blancco ISO in project directory
@@ -106,91 +106,76 @@ if [ -n "$BLANCCO_ISO" ] && [ -f "$BLANCCO_ISO" ]; then
echo " Extracted Blancco boot files."
# --- Patch config.img (size-preserving) ---
- # config.img is a CPIO archive containing preferences.xml (padded to 32768 bytes).
- # The CPIO itself must remain exactly 194560 bytes (380 x 512-byte blocks).
- # We use Python for byte-level replacement to preserve exact sizes.
+ # config.img is a CPIO archive. Its preferences.xml is what the native
+ # kernel (BIOS) boot path reads; the UEFI path gets the same file over
+ # HTTP. Both now carry playbook/blancco-preferences.xml, so the two
+ # paths cannot drift. The vendor file is laid out as
+ # [NUL padding] and its size is kept:
+ # 7.20 pads to 32768 with ~15KB of NULs; 7.15 had none, so growth
+ # there comes out of the filler comment.
if [ -f "$OUT_DIR/blancco/config.img" ]; then
- echo " Patching config.img for network report storage..."
+ echo " Writing playbook preferences into config.img..."
CFGTMP=$(mktemp -d)
cd "$CFGTMP"
cpio -id < "$OUT_DIR/blancco/config.img" 2>/dev/null
if [ -f "$CFGTMP/preferences.xml" ]; then
- ORIG_SIZE=$(stat -c%s "$CFGTMP/preferences.xml")
-
- python3 << 'PYEOF'
-import sys
+ PREFS_SRC="$REPO_ROOT/playbook/blancco-preferences.xml" python3 << 'PYEOF'
+import os, re, sys
with open("preferences.xml", "rb") as f:
data = f.read()
-
+with open(os.environ["PREFS_SRC"], "rb") as f:
+ ours = f.read().strip() + b"\n"
orig_size = len(data)
-# Set SMB share credentials and path
-data = data.replace(
- b'',
- b'blancco'
-)
-data = data.replace(
- b'',
- b'blancco'
-)
-data = data.replace(
- b'',
- b'172.16.9.1'
-)
-data = data.replace(
- b'',
- b'blancco-reports'
-)
+def version(x):
+ m = re.search(rb"\s*(\d+)\s*"
+ rb"(\d+)", x)
+ return m.groups() if m else None
-# Enable auto-backup
-data = data.replace(
- b'false',
- b'true'
-)
+# Our file must be a merge onto THIS release's preferences, or settings the
+# new schema added or renamed are silently lost.
+if version(ours) != version(data):
+ sys.exit(f" ERROR: playbook preferences are for {version(ours)}, ISO is "
+ f"{version(data)}. Merge onto the new vendor preferences first.")
+for need in (b"172.16.9.1", b"blancco-reports",
+ b"true"):
+ if need not in ours:
+ sys.exit(f" ERROR: playbook preferences missing {need.decode()}")
-# Enable bootable report
-data = data.replace(
- b'\n false\n ',
- b'\n true\n '
-)
-
-# Maintain exact file size by trimming trailing padding/whitespace
-diff = len(data) - orig_size
-if diff > 0:
- # The file has trailing whitespace/padding before the final XML closing tags
- # Trim from the padding area (spaces before closing comment or end of file)
- end_pos = data.rfind(b'', end_pos)
- if comment_end > 0:
- data = data[:comment_end - diff] + data[comment_end:]
- if len(data) > orig_size:
- # Fallback: trim trailing whitespace
- data = data.rstrip()
- data = data + b'\n' * (orig_size - len(data))
-elif diff < 0:
- # Pad with spaces to maintain size
- data = data[:-1] + b' ' * (-diff) + data[-1:]
-
-if len(data) != orig_size:
- print(f" WARNING: Size mismatch ({len(data)} vs {orig_size}), padding to match")
- if len(data) > orig_size:
- data = data[:orig_size]
- else:
- data = data + b'\x00' * (orig_size - len(data))
+# Split off the trailing filler comment and any NUL padding before it.
+end = data.find(b"")
+cstart = data.rfind(b"").
+ cut = -room
+ if len(tail) - cut < len(b"\n"):
+ sys.exit(f" ERROR: preferences need {cut} more bytes than the "
+ "padding and filler comment can give")
+ tail = tail[:5] + tail[5 + cut:]
+ gap = b""
+out = xml + gap + tail
+if len(out) != orig_size:
+ sys.exit(f" ERROR: preferences.xml size changed {orig_size} -> {len(out)}")
with open("preferences.xml", "wb") as f:
- f.write(data)
-
-print(f" preferences.xml: {orig_size} bytes (preserved)")
+ f.write(out)
+print(f" preferences.xml: {len(xml)} bytes of XML, {orig_size} total (preserved)")
PYEOF
- # Repack CPIO with exact 512-byte block alignment (194560 bytes)
+ # Repack CPIO padded to a 512-byte boundary
ls -1 "$CFGTMP" | (cd "$CFGTMP" && cpio -o -H newc 2>/dev/null) | \
dd bs=512 conv=sync 2>/dev/null > "$OUT_DIR/blancco/config.img"
- echo " Reports: SMB blancco@172.16.9.1/blancco-reports, bootable report enabled"
+ echo " Reports: SMB blancco@172.16.9.1/blancco-reports (from playbook preferences)"
fi
cd "$REPO_ROOT"
rm -rf "$CFGTMP"
@@ -201,41 +186,51 @@ PYEOF
# flush all network interfaces. Binary-patch the check from "y" to "N" so
# the condition never matches. IMPORTANT: full extract/repack BREAKS booting.
echo " Patching initramfs to preserve network after copytoram..."
- python3 << PYEOF
-import lzma, sys, os
-
-initramfs = "$OUT_DIR/blancco/initramfs-bde-linux.img"
+ INITRAMFS="$OUT_DIR/blancco/initramfs-bde-linux.img" python3 << 'PYEOF'
+import lzma, os, sys
+initramfs = os.environ["INITRAMFS"]
with open(initramfs, "rb") as f:
- compressed = f.read()
+ data = f.read()
-# Decompress XZ stream
-try:
- raw = lzma.decompress(compressed)
-except lzma.LZMAError:
- print(" WARNING: Could not decompress initramfs (not XZ?), skipping patch")
- sys.exit(0)
+# 7.20 prepends an uncompressed early cpio (NIC firmware) before the XZ
+# archive; 7.15 was XZ from byte 0. Patch only the XZ part, keep the prefix.
+# Walk the cpio headers to its trailer: the firmware files are themselves
+# .xz, so searching for the XZ magic would land inside the prefix.
+off = 0
+while data.startswith(b"070701", off):
+ namesize = int(data[off + 94:off + 102], 16)
+ filesize = int(data[off + 54:off + 62], 16)
+ name = data[off + 110:off + 110 + namesize - 1]
+ off = (((off + 110 + namesize + 3) & ~3) + filesize + 3) & ~3
+ if name == b"TRAILER!!!":
+ while off < len(data) and data[off] == 0:
+ off += 1
+if not data.startswith(b"\xfd7zXZ\x00", off):
+ sys.exit(f" ERROR: initramfs layout not recognised (no XZ archive at {off})")
+prefix, compressed = data[:off], data[off:]
-# Binary patch: change the copytoram check from "y" to "N"
+raw = lzma.decompress(compressed)
+
+# Binary patch: change the copytoram check from "y" to "N" in
+# archiso_pxe_common's run_latehook. Exact match only: the looser
+# '"${copytoram}" = "y"' appears in several hooks and patching the first
+# one found is not safe.
old = b'"y" ]; then\n for curif in /sys/class/net'
new = b'"N" ]; then\n for curif in /sys/class/net'
+count = raw.count(old)
+if count != 1:
+ sys.exit(f" ERROR: copytoram network-flush pattern found {count} times, "
+ "expected 1. PXE boot would lose network after copytoram.")
+raw = raw.replace(old, new, 1)
-if old not in raw:
- # Try alternate pattern with different whitespace
- old = b'"\${copytoram}" = "y"'
- new = b'"\${copytoram}" = "N"'
-
-if old in raw:
- raw = raw.replace(old, new, 1)
- # Recompress with same XZ settings as archiso
- recompressed = lzma.compress(raw, format=lzma.FORMAT_XZ,
- check=lzma.CHECK_CRC32,
- preset=6)
- with open(initramfs, "wb") as f:
- f.write(recompressed)
- print(" initramfs patched: copytoram network flush disabled")
-else:
- print(" WARNING: copytoram pattern not found in initramfs, skipping patch")
+# Recompress with same XZ settings as archiso
+recompressed = lzma.compress(raw, format=lzma.FORMAT_XZ,
+ check=lzma.CHECK_CRC32, preset=6)
+with open(initramfs, "wb") as f:
+ f.write(prefix + recompressed)
+print(f" initramfs patched: copytoram network flush disabled "
+ f"(early cpio {len(prefix)} bytes kept)")
PYEOF
# --- Build GRUB EFI binary for Blancco chainload ---