From 307aa5535649cedcbf1b6fae3337aef1ff45b99e Mon Sep 17 00:00:00 2001 From: Tero Date: Fri, 4 Sep 2026 16:13:00 +0300 Subject: [PATCH] Add ability to use random data or zeroes --- README.md | 16 ++++++++++-- erase-zfs-metadata.sh | 57 +++++++++++++++++++++++++++++++++++++------ 2 files changed, 64 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index db72198..a7a7144 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,9 @@ device after it has been cleanly removed from its pool. ## What It Erases -The script performs 10 overwrite passes with zeroes over the first 4 MiB and -the last 4 MiB of the target block device. These regions include: +The script performs 10 overwrite passes over the first 4 MiB and the last +4 MiB of the target block device. It uses zeroes by default and can use random +data when requested. These regions include: - MBR data and GPT primary partition table at the beginning of a disk. - GPT backup partition table at the end of a disk. @@ -41,6 +42,17 @@ chmod +x erase-zfs-metadata.sh sudo ./erase-zfs-metadata.sh /dev/sdX ``` +Use `--source random` to overwrite with data from `/dev/urandom` instead of +the default zeroes: + +```bash +sudo ./erase-zfs-metadata.sh --source random /dev/sdX +``` + +The only accepted source values are `zeroes` and `random`. Random overwrites +are typically slower and do not erase additional parts of the device; both +modes overwrite the same first and last 4 MiB regions. + Replace `/dev/sdX` with the actual device, such as `/dev/sdb`, `/dev/nvme0n1`, or a device-mapper path. Do not use the disk containing the running system. diff --git a/erase-zfs-metadata.sh b/erase-zfs-metadata.sh index 5d3f9bb..426cd32 100644 --- a/erase-zfs-metadata.sh +++ b/erase-zfs-metadata.sh @@ -10,11 +10,16 @@ readonly WIPE_BYTES=$((WIPE_MIB * MIB)) usage() { cat <<'EOF' -Usage: sudo ./erase-zfs-metadata.sh /dev/ +Usage: sudo ./erase-zfs-metadata.sh [--source zeroes|random] /dev/ Overwrites the first and last 4 MiB of the specified block device ten times. This destroys MBR/GPT partition tables and all conventional ZFS vdev labels. The device must not be mounted or part of an imported ZFS pool. + +Options: + --source zeroes Write zeroes from /dev/zero (default). + --source random Write random data from /dev/urandom. + -h, --help Show this help message. EOF } @@ -23,11 +28,49 @@ die() { exit 1 } -[[ $# -eq 1 ]] || { usage >&2; exit 2; } -device=$1 +write_source=/dev/zero +source_name=zeroes +device= + +while [[ $# -gt 0 ]]; do + case $1 in + --source) + [[ $# -ge 2 ]] || die '--source requires zeroes or random.' + case $2 in + zeroes) + write_source=/dev/zero + source_name=zeroes + ;; + random) + write_source=/dev/urandom + source_name=random + ;; + *) + die "invalid source '$2'; use zeroes or random." + ;; + esac + shift 2 + ;; + -h|--help) + usage + exit 0 + ;; + -*) + die "unknown option '$1'." + ;; + *) + [[ -z $device ]] || die 'specify exactly one block device.' + device=$1 + shift + ;; + esac +done + +[[ -n $device ]] || { usage >&2; exit 2; } [[ $EUID -eq 0 ]] || die 'run as root (for example, with sudo).' [[ -b $device ]] || die "'$device' is not a block device." +[[ -r $write_source ]] || die "'$write_source' is not readable." for command in blockdev dd findmnt lsblk zpool; do command -v "$command" >/dev/null 2>&1 || die "required command '$command' was not found." @@ -50,16 +93,16 @@ size_bytes=$(blockdev --getsize64 "$device") last_offset=$((size_bytes - WIPE_BYTES)) -printf '\nWARNING: this permanently destroys partition tables and ZFS metadata on:\n %s\n\n' "$device" +printf '\nWARNING: this permanently destroys partition tables and ZFS metadata on:\n %s\nusing %s data.\n\n' "$device" "$source_name" lsblk --output NAME,SIZE,TYPE,MOUNTPOINTS "$device" read -r -p "Type exactly 'ERASE $device' to continue: " confirmation [[ $confirmation == "ERASE $device" ]] || die 'confirmation did not match; no data was changed.' for ((pass = 1; pass <= PASSES; pass++)); do printf 'Pass %d/%d...\n' "$pass" "$PASSES" - dd if=/dev/zero of="$device" bs="$MIB" count="$WIPE_MIB" conv=fsync,notrunc status=none - dd if=/dev/zero of="$device" bs=1 count="$WIPE_BYTES" seek="$last_offset" conv=fsync,notrunc status=none + dd if="$write_source" of="$device" bs="$MIB" count="$WIPE_MIB" conv=fsync,notrunc status=none + dd if="$write_source" of="$device" bs=1 count="$WIPE_BYTES" seek="$last_offset" conv=fsync,notrunc status=none done sync -printf 'Completed %d overwrite passes on %s.\n' "$PASSES" "$device" \ No newline at end of file +printf 'Completed %d %s overwrite passes on %s.\n' "$PASSES" "$source_name" "$device" \ No newline at end of file