#!/usr/bin/env bash # SPDX-License-Identifier: GPL-3.0-or-later # Craig Jennings # identify disk and erase # Overridable so the test suite can point at a fixture directory, the way # nvidia_preflight_report takes NVIDIA_DRM_GLOB. by_id_dir="${WIPEDISK_BY_ID:-/dev/disk/by-id}" # Whole disks only. /dev/disk/by-id publishes a -partN entry for every # partition alongside the disks (18 entries on this machine, 12 of them # partitions), and the prompt below promises a disk. Globbed rather than # `ls | grep` so a name with whitespace can't split into two menu entries. all_disk_ids=() for entry in "$by_id_dir"/*; do [ -e "$entry" ] || continue # unmatched glob stays literal name="${entry##*/}" [[ "$name" =~ -part[0-9]+$ ]] && continue all_disk_ids+=("$name") done if [ "${#all_disk_ids[@]}" -eq 0 ]; then echo "No disks found in $by_id_dir." >&2 exit 1 fi echo ""; echo "Select the disk id to use. All data will be erased." select disk_id in "${all_disk_ids[@]}"; do # ensure valid selection if [[ -n $disk_id ]]; then selection=$disk_id break else echo "Invalid. Try again." fi done # Confirm the selected disk read -r -p "Confirm: '$selection' [y/n]? " choice if [[ "$choice" != "y" ]]; then echo "Exiting..." exit 1 fi DISK="$by_id_dir/$selection" echo ""; echo "### Erasing Disk" # blkdiscard opens the device O_EXCL by default (util-linux >= 2.36) and # refuses a disk something is holding -- a mounted filesystem, an md member, an # LVM PV. That refusal is this script's safety gate, and it has to run BEFORE # anything destructive. Passing -f disables the exclusive open, which turned # "refuse the wrong disk" into "discard a live filesystem, then let sgdisk fail # and tell the user nothing happened". The gate is the kernel's answer, not a # heuristic of ours, so no -f. discarded=true discard_err=$(blkdiscard "${DISK}" 2>&1) || discarded=false # A discard can fail for two very different reasons. "Operation not supported" # means the hardware has no discard -- the run continues and the closing # message says the data is still there. Anything else means the device was # refused, and nothing has been written yet, so stop while that is still true. if [ "$discarded" = false ] \ && ! printf '%s' "$discard_err" | grep -qi 'not supported'; then echo "" >&2 echo "REFUSED: '$selection' is in use. Nothing was erased." >&2 [ -n "$discard_err" ] && echo " $discard_err" >&2 echo " Unmount its filesystems and stop any md/LVM/ZFS holder, then run" >&2 echo " this again." >&2 exit 1 fi # sgdisk refuses a busy device too. Reaching here means blkdiscard already # accepted the disk, so a failure now is something else -- report it rather # than announcing an erase that did not happen. if ! sgdisk --zap-all "${DISK}"; then echo "" >&2 echo "FAILED: could not clear the partition table on '$selection'." >&2 echo " The sectors were discarded but the partition table was not" >&2 echo " rewritten. Check the device and run this again." >&2 exit 1 fi echo "" if [ "$discarded" = true ]; then echo "Disk erased. Sectors discarded and the partition table cleared." else # Say what actually happened. sgdisk --zap-all destroys partition tables, # not data, so without a successful discard every byte is still readable. echo "Partition table cleared on '$selection'." echo "NOTE: this device did not support discard, so the data is still" echo " present and recoverable. For a disposal-grade wipe use the" echo " drive's own secure erase (nvme format, hdparm) or overwrite it." fi