From b0348ea45df82db24702fca7cba85d23eaf3b07b Mon Sep 17 00:00:00 2001 From: Josh Ashton Date: Thu, 6 Aug 2026 10:52:53 -0600 Subject: [PATCH] saving files --- drive_map.sh | 80 ++++++++++ old-wipe.sh | 54 +++++++ wipe-2.sh | 379 ++++++++++++++++++++++++++++++++++++++++++++++ wipe-sata.sh | 412 +++++++++++++++++++++++++++++++++++++++++++++++++++ wipe.sh | 370 +++++++++++++++++++++++++++++++++++++++++++++ wipe2.sh | 98 ++++++++++++ 6 files changed, 1393 insertions(+) create mode 100755 drive_map.sh create mode 100644 old-wipe.sh create mode 100755 wipe-2.sh create mode 100755 wipe-sata.sh create mode 100755 wipe.sh create mode 100755 wipe2.sh diff --git a/drive_map.sh b/drive_map.sh new file mode 100755 index 0000000..6c6a6c8 --- /dev/null +++ b/drive_map.sh @@ -0,0 +1,80 @@ +#!/usr/bin/env python3 +import os +import sys +import re + +# Physical mapping updated to 1-based indexing: (Row 1-6, Column 1-4) +BAY_MAP = { + "0000:01": { + "phy0": (1, 1), "phy1": (1, 2), "phy2": (1, 3), "phy3": (1, 4), + "phy4": (2, 1), "phy5": (2, 2), "phy6": (2, 3), "phy7": (2, 4), + }, + "0000:02": { + "phy0": (3, 4), "phy1": (3, 3), "phy2": (3, 2), "phy3": (3, 1), + "phy4": (4, 4), "phy5": (4, 3), "phy6": (4, 2), "phy7": (4, 1), + }, + "0000:04": { + "phy0": (5, 4), "phy1": (5, 3), "phy2": (5, 2), "phy3": (5, 1), + "phy4": (6, 4), "phy5": (6, 3), "phy6": (6, 2), "phy7": (6, 1), + } +} + +def main(): + export_mapping = (len(sys.argv) > 1 and sys.argv[1] == "--mapping") + + # Initialize a 6x4 empty grid (1-indexed rows 1-6, columns 1-4) + # We use size 7x5 internally so we can just use the indices 1 to 6 and 1 to 4 directly + grid = [["[ EMPTY ]" for _ in range(5)] for _ in range(7)] + path_dir = "/dev/disk/by-path" + + if not os.path.exists(path_dir): + if not export_mapping: + print(f"Error: {path_dir} does not exist.") + return + + sas_regex = re.compile(r"pci-(0000:\d{2}):\d{2}\.\d-sas-(phy\d)-lun-0") + mappings = {} + + for filename in os.listdir(path_dir): + match = sas_regex.match(filename) + if match: + pci_addr = match.group(1) + phy_id = match.group(2) + + if pci_addr in BAY_MAP and phy_id in BAY_MAP[pci_addr]: + row, col = BAY_MAP[pci_addr][phy_id] + full_path = os.path.join(path_dir, filename) + try: + target = os.readlink(full_path) + dev_name = os.path.basename(target) + grid[row][col] = f"[ /dev/{dev_name} ]" + mappings[dev_name] = f"R{row}-C{col}" + except OSError: + grid[row][col] = "[ ERROR ]" + + # Bash Mode: Output "sda:R1-C3" format + if export_mapping: + for dev, bay in mappings.items(): + print(f"{dev}:{bay}") + return + + # Visual Mode: Print your layout chart for the operators + print("\n" + "="*53) + print(" DRIVE WIPING BAY LAYOUT ") + print("="*53) + + # Iterate from Row 1 to 6 + for row_idx in range(1, 7): + # Slice columns 1 through 4 + row_cells = grid[row_idx][1:5] + row_str = " | ".join(f"{cell:<11}" for cell in row_cells) + print(f"Row {row_idx}: | {row_str} |") + + # Add visual separation between shelf units + if row_idx in [2, 4]: + print("-" * 53) + + print("="*53 + "\n") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/old-wipe.sh b/old-wipe.sh new file mode 100644 index 0000000..5e24a80 --- /dev/null +++ b/old-wipe.sh @@ -0,0 +1,54 @@ + + (pkgs.writeShellScriptBin "wipe" '' + echo "Detecting in 15 seconds..." + sleep 10 + echo 1 > /sys/bus/pci/rescan + sleep 5 + + if [ ! -e "/dev/nvme0n1" ]; then + echo "Rebooting in 3 seconds. If still not detected, NVMe is DOA." + sleep 3 + reboot + else + echo "NVMe detected!" + fi + + mkdir -p "/home/nps/logs" + SN="$(nvme id-ctrl /dev/nvme0n1 | awk '/^[[:space:]]*sn[[:space:]]*:/ {print $3; exit}')" + LOG_FILE="/home/nps/logs/$SN.log" + touch "$LOG_FILE" + + echo "Wiping NVMe..." + nvme format /dev/nvme0n1 --ses=1 --force | tee "$LOG_FILE" + WIPE_STATUS=''${PIPESTATUS[0]} + + smartctl -a /dev/nvme0n1 | tee -a "$LOG_FILE" + SMART_STATUS=''${PIPESTATUS[0]} + + echo "Resetting parent PCIe bridge ($PARENT_BRIDGE) resources to disconnect NVMe in 15 seconds..." + echo 1 > "/sys/bus/pci/devices/0000:09:00.0/remove" + + sleep 15 + + echo "NVMe disconnected and is safe to remove." + echo "" + + # --- Final Confirmation --- + echo "===================================" + echo " RESULTS SUMMARY " + echo "===================================" + + if [ "$WIPE_STATUS" -eq 0 ]; then + echo "WIPE: [ SUCCESS ]" + else + echo "WIPE: [ FAILED ]" + fi + + if [ "$SMART_STATUS" -eq 0 ]; then + echo "SMART: [ PASSED ]" + else + echo "SMART: [ FAILED ]" + fi + + echo "===================================" + '') diff --git a/wipe-2.sh b/wipe-2.sh new file mode 100755 index 0000000..d8819b9 --- /dev/null +++ b/wipe-2.sh @@ -0,0 +1,379 @@ +CONFIG_FILE="/home/nps/.config/wipe.conf" # Configuration file location. DO NOT CHANGE! +EXCLUDE_DEVICE="/dev/nvme0n1" # Boot drive, should not be changed. DO NOT CHANGE! + +BUS_TYPE="" # NVMe wipe protocol by default. +MEDIA_TYPE="" # SSD by default. +DEVICE="" # Default device +LOG_FILE="" + +wipe-confirmation() { + local wipe_status="$1" + local smart_status="$2" + + if [ "$wipe_status" -eq 0 ]; then + wipe_status="WIPE: [ SUCCESS ]" + else + wipe_status="WIPE: [ FAILED ]" + fi + + if [ "$smart_status" -eq 0 ]; then + smart_status="SMART: [ PASSED ]" + else + smart_status="SMART: [ FAILED ]" + fi + + { echo " +=================================== + RESULTS SUMMARY +=================================== + + $wipe_status + + $smart_status + +=================================== + "; cat "$LOG_FILE"; } > tmp.log && mv tmp.log $LOG_FILE + + + echo " +=================================== + RESULTS SUMMARY +=================================== + + $wipe_status + + $smart_status + +=================================== + " +} + +smart-info() { + smartctl -a "$DEVICE" >> "$LOG_FILE" 2>&1 + return ${PIPESTATUS[0]} +} + +init-log() { + mkdir -p "/home/nps/logs" + + SN="$(smartctl -a "$DEVICE" | awk '/Serial Number:/ {print $3; exit}')" + LOG_FILE="/home/nps/logs/$SN.log" + echo "" > "$LOG_FILE" +} + +verify-wipe() { + local wipe_status + echo "Verifying wipe..." | tee -a "$LOG_FILE" + sleep 2 + + if dd if="$DEVICE" bs=1M count=1024 status=none | cmp -n 1073741824 -l - /dev/zero; then + echo "Verification passed." | tee -a "$LOG_FILE" + wipe_status=0 + else + echo "Verification failed." | tee -a "$LOG_FILE" + wipe_status=1 + fi + + return "$wipe_status" +} + +# Returns 0 if ready, 1 if unsupported, 2 if frozen/aborted. +sata-ssd-security-state() { + local status + status=$(sudo hdparm -I "$DEVICE") + + # Check if supported + if ! echo "$status" | grep -q "supported"; then + echo "Error: Drive does not support ATA security features." + return 1 # Unsupported + fi + + # Check if frozen + if echo "$status" | grep -q "frozen" | grep -v -q "not"; then + echo "Error: Drive is in a 'frozen' state. Hot-plug required." + read -p "Has drive been hot-plugged? (y/N)" -r -n 1 + echo + + if [[ "$REPLY" =~ ^[Yy]$ ]]; then + sata-ssd-security-state + return $? + fi + + return 2 # Frozen/aborted by user. + fi + + return 0 # Ready +} + +wipe-sata-ssd() { + local wipe_status + + echo "Checking security state..." + sata-ssd-security-state + local state=$? + + case $state in + "0") + echo "Executing ATA Secure Erase..." | tee -a "$LOG_FILE" + hdparm --user-master u --security-set-pass p "$DEVICE" >> "$LOG_FILE" 2>&1 + hdparm --user-master u --security-erase p "$DEVICE" >> "$LOG_FILE" 2>&1 + wipe_status=$? + ;; + "1") + echo "ATA Security not supported. Falling back to blkdiscard..." | tee -a "$LOG_FILE" + blkdiscard --secure "$DEVICE" >> "$LOG_FILE" 2>&1 + wipe_status=$? + ;; + "2") + echo "Aborted: Drive is frozen or user declined hot-plug." + return 2 + ;; + *) + echo "Unknown state returned." + return 1 + ;; + esac + + if [ $wipe_status -eq 0 ]; then + blockdev --rereadpt "$DEVICE" + partprobe "$DEVICE" + udevadm settle + + verify-wipe + wipe_status=$? + fi + + # Write SMART info to LOG and save result for confirmation display. + smart-info + wipe-confirmation "$wipe_status" "$?" + echo -e "\n\nSATA SSD wipe complete and ready to remove." +} + +wipe-hdd() { + echo "Wiping HDD..." | tee -a "$LOG_FILE" + shred -vz -n 1 "$DEVICE" + local wipe_status=$? + + if [ $wipe_status -eq 0 ]; then + verify-wipe + wipe_status=$? + fi + + # Write SMART info to LOG and save result for confirmation display. + smart-info + wipe-confirmation "$wipe_status" "$?" + echo -e "\n\nHDD wipe complete and ready to remove." +} + +wipe-emmc() { + echo "Wiping eMMC..." | tee -a "$LOG_FILE" + blkdiscard "$DEVICE" >> "$LOG_FILE" 2>&1 + local wipe_status=$? + + if [ $wipe_status -eq 0 ]; then + verify-wipe + wipe_status=$? + fi + + # Write SMART info to LOG and save result for confirmation display. + smart-info + wipe-confirmation "$wipe_status" "$?" + echo -e "\n\neMMC wipe complete and ready to remove." +} + +wipe-usb() { + echo "Wiping USB..." | tee -a "$LOG_FILE" + shred -vz -n 1 "$DEVICE" + local wipe_status=$? + + if [ $wipe_status -eq 0 ]; then + verify-wipe + wipe_status=$? + fi + + # Write SMART info to LOG and save result for confirmation display. + smart-info + wipe-confirmation "$wipe_status" "$?" + echo -e "\n\nUSB wipe complete and ready to remove." +} + +wipe-nvme() { + # Wipe NVMe via Secure Erase NVMe feature. + echo "Wiping NVMe..." + nvme format "$DEVICE" --ses=1 --force >> "$LOG_FILE" 2>&1 + local wipe_status=$? + + # Write SMART info to LOG and save result for confirmation display. + smart-info + local smart_status=$? + + # Dynamic disconnect of NVMe drive + local dev_node="${DEVICE#/dev/}" + local pci_path=$(readlink -f "/sys/block/$dev_node/device" | xargs basename) + echo "NVMe disconnect will take 15 seconds..." + echo 1 > "/sys/bus/pci/devices/$pci_path/remove" + sleep 15 + + wipe-confirmation "$wipe_status" "$smart_status" + echo -e "\n\nNVMe disconnected and is safe to remove." +} + +show-help() { + echo ' +Created by Josh Ashton +Last modified: 20-07-2026 +Email: me@joshashton.dev +Secondary Email: joshua.ashton@npsstore.com + +Drive wiping utility for various drive types. + +Usage: + + - `wipe` + Use default wipe method (NVMe SSD format) + + - `wipe -h` & `wipe --help` + Show this help page. + Cannot be combined with other arguments. + + - `wipe -b nvme` & `wipe --bus-type nvme` + Set the bus type that a drive is connected to (ie. nvme, sata). nvme is + the default bus type. And will automatically set the media type to SSD. + Use without providing a bus type to list available bus types. + + - `wipe -m ssd` & `wipe --media-type ssd` + Set the media type to wipe (ie. ssd, hdd, emmc, usb). ssd is the + default media type. + Use without providing a media type to list available media types. + + - `wipe -d /dev/nvme0n1` & `wipe --device /dev/nvme0n1` + Set the device to wipe. Defaults to the first device of the bus type. + Use without providing a device to list available devices. + + - `wipe -c` & `wipe --configure` + Perform guided configuration to set new defaults. Changes are persistent + and can be directly edited at `$HOME/.config/wipe.conf`. + Cannot be combined with other arguments. + + Arguments can be combined for more control: + - `wipe -b sata -m hdd -d /dev/sdb` + ' + + exit +} + +detect-device() { + if [[ "$BUS_TYPE" == "nvme" ]]; then + echo "Detecting in 15 seconds..." + sleep 10 + echo 1 > /sys/bus/pci/rescan + sleep 5 + + if [ ! -e "$DEVICE" ]; then + echo "Rebooting in 3 seconds. If still not detected, NVMe is DOA." + sleep 3 + reboot + else + echo "NVMe detected!" + fi + elif [[ "$BUS_TYPE" == "sata" && "$MEDIA_TYPE" == "ssd" ]]; then + udevadm trigger + + if [ ! -e "$DEVICE" ]; then + echo "Drive is DOA." + exit 1 + fi + fi + + init-log +} + +run-wipe() { + # Safety check + if [[ "$DEVICE" == "$EXCLUDE_DEVICE" ]] || grep -q "$DEVICE" /proc/mounts; then + echo "CRITICAL ERROR: Attempted to wipe protected or mounted device: $DEVICE" + exit 1 + fi + + case "$BUS_TYPE:$MEDIA_TYPE" in + nvme:ssd) wipe-nvme ;; + sata:ssd) wipe-sata-ssd ;; + *:hdd) wipe-hdd ;; + *:emmc) wipe-emmc ;; + *:usb) wipe-usb ;; + *) echo "Unsupported configuration: $BUS_TYPE/$MEDIA_TYPE"; exit 1 ;; + esac +} + +configure-wipe() { + # 1. Select Bus Type + BUS_TYPE=$(dialog --title "Bus Type" --menu "Select bus type:" 15 60 4 \ + "nvme" "NVMe Drive" \ + "sata" "SATA Drive" \ + "usb" "USB Storage" 3>&1 1>&2 2>&3) || exit + + # 2. Select Media Type + MEDIA_TYPE=$(dialog --title "Media Type" --menu "Select media type:" 15 60 4 \ + "ssd" "Solid State Drive" \ + "hdd" "Hard Disk Drive" \ + "emmc" "eMMC Flash" 3>&1 1>&2 2>&3) || exit + + # 3. Select Device (Dynamic list of block devices) + local dev_list=() + while read -r dev; do + dev_list+=("$dev" "Available device") + done < <(lsblk -dpno NAME | grep -v "$EXCLUDE_DEVICE") + + if [ "${#dev_list[@]}" -eq 0 ]; then + dialog --msgbox "No available drives detected." 8 40 + clear + exit 1 + fi + + DEVICE=$(dialog --title "Device Selection" --menu "Select device to wipe:" 15 60 10 \ + "${dev_list[@]}" 3>&1 1>&2 2>&3) || exit + + # 4. Save to Config + mkdir -p "$(dirname "$CONFIG_FILE")" + echo " +BUS_TYPE=$BUS_TYPE +MEDIA_TYPE=$MEDIA_TYPE +DEVICE=$DEVICE + " > "$CONFIG_FILE" + + dialog --msgbox "Configuration saved to $CONFIG_FILE" 8 40 + clear + exit 0 +} + +main() { + local GETOPT_BIN="/run/current-system/sw/bin/getopt" + [ -f "$CONFIG_FILE" ] && source "$CONFIG_FILE" + + local OPTS + OPTS=$("$GETOPT_BIN" -o b:m:d:hc -l bus-type:,media-type:,device:,help,configure -- "$@") + if [ $? -ne 0 ]; then help; exit 1; fi + eval set -- "$OPTS" + + while true; do + case "$1" in + -b|--bus-type) BUS_TYPE="$2"; shift 2 ;; + -m|--media-type) MEDIA_TYPE="$2"; shift 2 ;; + -d|--device) DEVICE="$2"; shift 2 ;; + -h|--help) show-help ;; + -c|--configure) configure-wipe ;; + --) shift; break ;; + *) echo "Unexpected error"; help; exit 1 ;; + esac + done + + if [[ -z "$DEVICE" ]]; then + echo "Error: No device specified. Use -d or run -c to configure." + exit 1 + fi + init-log + detect-device + run-wipe +} + +main "$@" diff --git a/wipe-sata.sh b/wipe-sata.sh new file mode 100755 index 0000000..281c19e --- /dev/null +++ b/wipe-sata.sh @@ -0,0 +1,412 @@ +#!/bin/sh + +CONFIG_FILE="/home/nps/.config/wipe.conf" # Configuration file location. DO NOT CHANGE! +EXCLUDE_DEVICE="/dev/nvme0n1" # Boot drive, should not be changed. DO NOT CHANGE! + +BUS_TYPE="" # NVMe wipe protocol by default. +MEDIA_TYPE="" # SSD by default. +DEVICE="" # Default device +LOG_FILE="" + +wipe-confirmation() { + local wipe_status="$1" + local smart_status="$2" + + if [ "$wipe_status" -eq 0 ]; then + wipe_status="WIPE: [ SUCCESS ]" + else + wipe_status="WIPE: [ FAILED ]" + fi + + if [ $(("$smart_status" & 24)) -eq 0 ] || "$smart_status" -eq 0; then + smart_status="SMART: [ PASSED ]" + else + smart_status="SMART: [ FAILED ]" + fi + + { echo " +=================================== + RESULTS SUMMARY +=================================== + + $wipe_status + + $smart_status + +=================================== + "; cat "$LOG_FILE"; } > tmp.log && mv tmp.log $LOG_FILE + + + echo " +=================================== + RESULTS SUMMARY +=================================== + + $wipe_status + + $smart_status + +=================================== + " +} + +smart-info() { + if [[ "$BUS_TYPE" == "usb" ]]; then + smartctl -d sat -x "$DEVICE" >> "$LOG_FILE" 2>&1 + else + smartctl -a "$DEVICE" >> "$LOG_FILE" 2>&1 + fi + return ${PIPESTATUS[0]} +} + +init-log() { + mkdir -p "/home/nps/logs" + + if [ "$BUS_TYPE" == "usb" ]; then + SN="$(lsblk -no NAME,SERIAL | grep sda | head -n 1 | awk '{print $2}')" + else + SN="$(smartctl -a "$DEVICE" | awk '/Serial Number:/ {print $3; exit}')" + fi + + LOG_FILE="/home/nps/logs/$SN.log" + echo "" > "$LOG_FILE" +} + +verify-wipe() { + local wipe_status + echo "Verifying wipe..." | tee -a "$LOG_FILE" + sleep 2 + + if dd if="$DEVICE" bs=1M count=1024 status=none | cmp -n 1073741824 -l - /dev/zero; then + echo "Verification passed." | tee -a "$LOG_FILE" + wipe_status=0 + else + echo "Verification failed." | tee -a "$LOG_FILE" + wipe_status=1 + fi + + return "$wipe_status" +} + +# Returns 0 if ready, 1 if unsupported, 2 if frozen/aborted. +sata-ssd-security-state() { + local status + status=$(sudo hdparm -I "$DEVICE") + + # Check if supported + if ! echo "$status" | grep -q "supported"; then + echo "Error: Drive does not support ATA security features." + return 1 # Unsupported + fi + + # Check if frozen + if echo "$status" | grep -q "frozen" | grep -v -q "not"; then + echo "Error: Drive is in a 'frozen' state. Hot-plug required." + read -p "Has drive been hot-plugged? (y/N)" -r -n 1 + echo + + if [[ "$REPLY" =~ ^[Yy]$ ]]; then + sata-ssd-security-state + return $? + fi + + return 2 # Frozen/aborted by user. + fi + + return 0 # Ready +} + +wipe-sata-ssd() { + local wipe_status + + echo "Checking security state..." + sata-ssd-security-state + local state=$? + + case $state in + "0") + echo "Executing ATA Secure Erase..." | tee -a "$LOG_FILE" + hdparm --user-master u --security-set-pass p "$DEVICE" >> "$LOG_FILE" 2>&1 + hdparm --user-master u --security-erase p "$DEVICE" >> "$LOG_FILE" 2>&1 + wipe_status=$? + ;; + "1") + echo "ATA Security not supported. Falling back to blkdiscard..." | tee -a "$LOG_FILE" + blkdiscard --secure "$DEVICE" >> "$LOG_FILE" 2>&1 + wipe_status=$? + ;; + "2") + echo "Aborted: Drive is frozen or user declined hot-plug." + return 2 + ;; + *) + echo "Unknown state returned." + return 1 + ;; + esac + + if [ $wipe_status -eq 0 ]; then + blockdev --rereadpt "$DEVICE" + partprobe "$DEVICE" + udevadm settle + + verify-wipe + wipe_status=$? + fi + + # Write SMART info to LOG and save result for confirmation display. + smart-info + wipe-confirmation "$wipe_status" "$?" + echo -e "\n\nSATA SSD wipe complete and ready to remove." +} + +wipe-hdd() { + echo "Wiping HDD..." | tee -a "$LOG_FILE" + shred -vz -n 1 "$DEVICE" + local wipe_status=$? + + if [ $wipe_status -eq 0 ]; then + verify-wipe + wipe_status=$? + fi + + # Write SMART info to LOG and save result for confirmation display. + smart-info + wipe-confirmation "$wipe_status" "$?" + echo -e "\n\nHDD wipe complete and ready to remove." +} + +wipe-emmc() { + echo "Wiping eMMC..." | tee -a "$LOG_FILE" + blkdiscard "$DEVICE" >> "$LOG_FILE" 2>&1 + local wipe_status=$? + + if [ $wipe_status -eq 0 ]; then + verify-wipe + wipe_status=$? + fi + + # Write SMART info to LOG and save result for confirmation display. + smart-info + wipe-confirmation "$wipe_status" "$?" + echo -e "\n\neMMC wipe complete and ready to remove." +} + +wipe-usb() { + local raw_device="${DEVICE#/dev/}" + local kernel_mode=$(cat /sys/block/$raw_device/device/scsi_disk/*/provisioning_mode) + local wipe_status=4 + if $(sg_vpd --all "$DEVICE" | grep -q "LBPU=1") || [[ "$kernel_mode" == "unmap" ]]; then + + if [ "$kernel_mode" != "unmap" ]; then + echo "USB device supports UNMAP/TRIM mode, attempting to update provisioning mode..." | tee -a "$LOG_FILE" + echo "unmap" | tee "/sys/block/$raw_device/device/scsi_disk/*/provisioning_mode" + fi + + echo "Wiping USB via built-in UNMAP/TRIM mode..." | tee -a "$LOG_FILE" + blkdiscard "$DEVICE" + wipe_status=$? + + if [ $wipe_status != 0 ]; then + echo "UNMAP/TRIM mode wipe failed!" + fi + fi + + if [[ "$kernel_mode" == "full" || $wipe_status -ne 0 ]]; then + echo "USB device doesn't support UNMAP/TRIM mode, falling back to dd." | tee -a "$LOG_FILE" + + dd if=/dev/zero of="$DEVICE" bs=4M status=progress conv=fdatasync 2>&1 | tee -a "$LOG_FILE" + wipe_status=${PIPESTATUS[0]} + fi + + if [ $wipe_status -eq 0 ]; then + verify-wipe + wipe_status=$? + fi + + # Write SMART info to LOG and save result for confirmation display. + smart-info + wipe-confirmation "$wipe_status" "$?" + echo -e "\n\nUSB wipe complete and ready to remove." +} + +wipe-nvme() { + # Wipe NVMe via Secure Erase NVMe feature. + echo "Wiping NVMe..." + nvme format "$DEVICE" --ses=1 --force >> "$LOG_FILE" 2>&1 + local wipe_status=$? + + # Write SMART info to LOG and save result for confirmation display. + smart-info + local smart_status=$? + + # Dynamic disconnect of NVMe drive + local dev_node="${DEVICE#/dev/}" + local pci_path=$(readlink -f "/sys/block/$dev_node/device" | xargs basename) + echo "NVMe disconnect will take 15 seconds..." + echo 1 > "/sys/bus/pci/devices/$pci_path/remove" + sleep 15 + + wipe-confirmation "$wipe_status" "$smart_status" + echo -e "\n\nNVMe disconnected and is safe to remove." +} + +show-help() { + echo ' +Created by Josh Ashton +Last modified: 20-07-2026 +Email: me@joshashton.dev +Secondary Email: joshua.ashton@npsstore.com + +Drive wiping utility for various drive types. + +Usage: + + - `wipe` + Use default wipe method (NVMe SSD format) + + - `wipe -h` & `wipe --help` + Show this help page. + Cannot be combined with other arguments. + + - `wipe -b nvme` & `wipe --bus-type nvme` + Set the bus type that a drive is connected to (ie. nvme, sata). nvme is + the default bus type. And will automatically set the media type to SSD. + Use without providing a bus type to list available bus types. + + - `wipe -m ssd` & `wipe --media-type ssd` + Set the media type to wipe (ie. ssd, hdd, emmc, usb). ssd is the + default media type. + Use without providing a media type to list available media types. + + - `wipe -d /dev/nvme0n1` & `wipe --device /dev/nvme0n1` + Set the device to wipe. Defaults to the first device of the bus type. + Use without providing a device to list available devices. + + - `wipe -c` & `wipe --configure` + Perform guided configuration to set new defaults. Changes are persistent + and can be directly edited at `$HOME/.config/wipe.conf`. + Cannot be combined with other arguments. + + Arguments can be combined for more control: + - `wipe -b sata -m hdd -d /dev/sdb` + ' + + exit +} + +detect-device() { + if [[ "$BUS_TYPE" == "nvme" ]]; then + echo "Detecting in 15 seconds..." + sleep 10 + echo 1 > /sys/bus/pci/rescan + sleep 5 + + if [ ! -e "$DEVICE" ]; then + echo "Rebooting in 3 seconds. If still not detected, NVMe is DOA." + sleep 3 + reboot + else + echo "NVMe detected!" + fi + elif [[ "$BUS_TYPE" == "sata" && "$MEDIA_TYPE" == "ssd" ]]; then + udevadm trigger + + if [ ! -e "$DEVICE" ]; then + echo "Drive is DOA." + exit 1 + fi + fi + + init-log +} + +run-wipe() { + # Safety check + if [[ "$DEVICE" == "$EXCLUDE_DEVICE" ]] || grep -q "$DEVICE" /proc/mounts; then + echo "CRITICAL ERROR: Attempted to wipe protected or mounted device: $DEVICE" + exit 1 + fi + + case "$BUS_TYPE:$MEDIA_TYPE" in + nvme:ssd) wipe-nvme ;; + sata:ssd) wipe-sata-ssd ;; + *:hdd) wipe-hdd ;; + *:emmc) wipe-emmc ;; + usb:*) wipe-usb ;; + *) echo "Unsupported configuration: $BUS_TYPE/$MEDIA_TYPE"; exit 1 ;; + esac +} + +configure-wipe() { + # 1. Select Bus Type + BUS_TYPE=$(dialog --title "Bus Type" --menu "Select bus type:" 15 60 4 \ + "nvme" "NVMe Drive" \ + "sata" "SATA Drive" \ + "usb" "USB Storage" 3>&1 1>&2 2>&3) || exit + + # 2. Select Media Type + MEDIA_TYPE=$(dialog --title "Media Type" --menu "Select media type:" 15 60 4 \ + "ssd" "Solid State Drive" \ + "hdd" "Hard Disk Drive" \ + "emmc" "eMMC Flash" 3>&1 1>&2 2>&3) || exit + + # 3. Select Device (Dynamic list of block devices) + local dev_list=() + while read -r dev; do + dev_list+=("$dev" "Available device") + done < <(lsblk -dpno NAME | grep -v "$EXCLUDE_DEVICE") + + if [ "${#dev_list[@]}" -eq 0 ]; then + dialog --msgbox "No available drives detected." 8 40 + clear + exit 1 + fi + + DEVICE=$(dialog --title "Device Selection" --menu "Select device to wipe:" 15 60 10 \ + "${dev_list[@]}" 3>&1 1>&2 2>&3) || exit + + # 4. Save to Config + mkdir -p "$(dirname "$CONFIG_FILE")" + echo " +BUS_TYPE=$BUS_TYPE +MEDIA_TYPE=$MEDIA_TYPE +DEVICE=$DEVICE + " > "$CONFIG_FILE" + + dialog --msgbox "Configuration saved to $CONFIG_FILE" 8 40 + clear + exit 0 +} + +main() { + local GETOPT_BIN="/run/current-system/sw/bin/getopt" + [ -f "$CONFIG_FILE" ] && source "$CONFIG_FILE" + + local OPTS + OPTS=$("$GETOPT_BIN" -o b:m:d:hc -l bus-type:,media-type:,device:,help,configure -- "$@") + if [ $? -ne 0 ]; then help; exit 1; fi + eval set -- "$OPTS" + + while true; do + case "$1" in + -b|--bus-type) BUS_TYPE="$2"; shift 2 ;; + -m|--media-type) MEDIA_TYPE="$2"; shift 2 ;; + -d|--device) DEVICE="$2"; shift 2 ;; + -h|--help) show-help ;; + -c|--configure) configure-wipe ;; + --) shift; break ;; + *) echo "Unexpected error"; help; exit 1 ;; + esac + done + + if [[ -z "$DEVICE" ]]; then + echo "Error: No device specified. Use -d or run -c to configure." + exit 1 + fi + init-log + detect-device + run-wipe +} + +main "$@" diff --git a/wipe.sh b/wipe.sh new file mode 100755 index 0000000..a4a3b2a --- /dev/null +++ b/wipe.sh @@ -0,0 +1,370 @@ +CONFIG_FILE="$HOME/.config/wipe.conf" # Configuration file location. DO NOT CHANGE! +EXCLUDE_DEVICE="/dev/sda" # Boot drive, should not be changed. DO NOT CHANGE! + +BUS_TYPE="" # NVMe wipe protocol by default. +MEDIA_TYPE="" # SSD by default. +DEVICE="" # Default device +LOG_FILE="" + +wipe-confirmation() { + local wipe_status="$1" + local smart_status="$2" + + if [ "$wipe_status" -eq 0 ]; then + wipe_status="WIPE: [ SUCCESS ]" + else + wipe_status="WIPE: [ FAILED ]" + fi + + if [ "$smart_status" -eq 0 ]; then + smart_status="SMART: [ PASSED ]" + else + smart_status="SMART: [ FAILED ]" + fi + + { echo " +=================================== + RESULTS SUMMARY +=================================== + + $wipe_status + + $smart_status + +=================================== + "; cat "$LOG_FILE"; } > tmp.log && mv tmp.log $LOG_FILE + + + echo " +=================================== + RESULTS SUMMARY +=================================== + + $wipe_status + + $smart_status + +=================================== + " +} + +smart-info() { + smartctl -a "$DEVICE" >> "$LOG_FILE" 2>&1 + return ${PIPESTATUS[0]} +} + +init-log() { + mkdir -p "/home/nps/logs" + + SN="$(smartctl -a "$DEVICE" | awk '/Serial Number:/ {print $3; exit}')" + LOG_FILE="/home/nps/logs/$SN.log" + echo "" > "$LOG_FILE" +} + +verify-wipe() { + local wipe_status + echo "Verifying wipe..." | tee -a "$LOG_FILE" + sleep 2 + + if dd if="$DEVICE" bs=1M count=1024 status=none | cmp -s - /dev/zero; then + echo "Verification passed." | tee -a "$LOG_FILE" + wipe_status=0 + else + echo "Verification failed." | tee -a "$LOG_FILE" + wipe_status=1 + fi + + return "$wipe_status" +} + +# Returns 0 if ready, 1 if unsupported, 2 if frozen/aborted. +sata-ssd-security-state() { + local status + status=$(sudo hdparm -I "$DEVICE") + + # Check if supported + if ! echo "$status" | grep -q "supported"; then + echo "Error: Drive does not support ATA security features." + return 1 # Unsupported + fi + + # Check if frozen + if echo "$status" | grep -q "frozen"; then + echo "Error: Drive is in a 'frozen' state. Hot-plug required." + read -p "Has drive been hot-plugged? (y/N)" -r -n 1 + echo + + if [[ "$REPLY" =~ ^[Yy]$ ]]; then + sata-ssd-security-state + return $? + fi + + return 2 # Frozen/aborted by user. + fi + + return 0 # Ready +} + +wipe-sata-ssd() { + local wipe_status + + echo "Checking security state..." + sata-ssd-security-state + local state=$? + + case $state in + "0") + echo "Executing ATA Secure Erase..." | tee -a "$LOG_FILE" + hdparm --user-master u --security-set-pass p "$DEVICE" >> "$LOG_FILE" 2>&1 + hdparm --user-master u --security-erase p "$DEVICE" >> "$LOG_FILE" 2>&1 + wipe_status=$? + ;; + "1") + echo "ATA Security not supported. Falling back to blkdiscard..." | tee -a "$LOG_FILE" + blkdiscard --secure "$DEVICE" >> "$LOG_FILE" 2>&1 + wipe_status=$? + ;; + "2") + echo "Aborted: Drive is frozen or user declined hot-plug." + return 2 + ;; + *) + echo "Unknown state returned." + return 1 + ;; + esac + + if [ $wipe_status -eq 0 ]; then + verify-wipe + wipe_status=$? + fi + + # Write SMART info to LOG and save result for confirmation display. + smart-info + wipe-confirmation "$wipe_status" "$?" + echo -e "\n\nSATA SSD wipe complete and ready to remove." +} + +wipe-hdd() { + echo "Wiping HDD..." | tee -a "$LOG_FILE" + shred -vz -n 1 "$DEVICE" + local wipe_status=$? + + if [ $wipe_status -eq 0 ]; then + verify-wipe + wipe_status=$? + fi + + # Write SMART info to LOG and save result for confirmation display. + smart-info + wipe-confirmation "$wipe_status" "$?" + echo -e "\n\nHDD wipe complete and ready to remove." +} + +wipe-emmc() { + echo "Wiping eMMC..." | tee -a "$LOG_FILE" + blkdiscard "$DEVICE" >> "$LOG_FILE" 2>&1 + local wipe_status=$? + + if [ $wipe_status -eq 0 ]; then + verify-wipe + wipe_status=$? + fi + + # Write SMART info to LOG and save result for confirmation display. + smart-info + wipe-confirmation "$wipe_status" "$?" + echo -e "\n\neMMC wipe complete and ready to remove." +} + +wipe-usb() { + echo "Wiping USB..." | tee -a "$LOG_FILE" + shred -vz -n 1 "$DEVICE" + local wipe_status=$? + + if [ $wipe_status -eq 0 ]; then + verify-wipe + wipe_status=$? + fi + + # Write SMART info to LOG and save result for confirmation display. + smart-info + wipe-confirmation "$wipe_status" "$?" + echo -e "\n\nUSB wipe complete and ready to remove." +} + +wipe-nvme() { + # Wipe NVMe via Secure Erase NVMe feature. + echo "Wiping NVMe..." + nvme format "$DEVICE" --ses=1 --force >> "$LOG_FILE" 2>&1 + local wipe_status=$? + + # Write SMART info to LOG and save result for confirmation display. + smart-info + local smart_status=$? + + # Dynamic disconnect of NVMe drive + local dev_node="${DEVICE#/dev/}" + local pci_path=$(readlink -f "/sys/block/$dev_node/device" | xargs dirname | xargs dirname | xargs basename) + echo "NVMe disconnect will take 15 seconds..." + echo 1 > "/sys/bus/pci/devices/$pci_path/remove" + sleep 15 + + wipe-confirmation "$wipe_status" "$smart_status" + echo -e "\n\nNVMe disconnected and is safe to remove." +} + +show-help() { + echo ' +Created by Josh Ashton +Last modified: 20-07-2026 +Email: me@joshashton.dev +Secondary Email: joshua.ashton@npsstore.com + +Drive wiping utility for various drive types. + +Usage: + + - `wipe` + Use default wipe method (NVMe SSD format) + + - `wipe -h` & `wipe --help` + Show this help page. + Cannot be combined with other arguments. + + - `wipe -b nvme` & `wipe --bus-type nvme` + Set the bus type that a drive is connected to (ie. nvme, sata). nvme is + the default bus type. And will automatically set the media type to SSD. + Use without providing a bus type to list available bus types. + + - `wipe -m ssd` & `wipe --media-type ssd` + Set the media type to wipe (ie. ssd, hdd, emmc, usb). ssd is the + default media type. + Use without providing a media type to list available media types. + + - `wipe -d /dev/nvme0n1` & `wipe --device /dev/nvme0n1` + Set the device to wipe. Defaults to the first device of the bus type. + Use without providing a device to list available devices. + + - `wipe -c` & `wipe --configure` + Perform guided configuration to set new defaults. Changes are persistent + and can be directly edited at `$HOME/.config/wipe.conf`. + Cannot be combined with other arguments. + + Arguments can be combined for more control: + - `wipe -b sata -m hdd -d /dev/sdb` + ' + + exit +} + +detect-device() { + if [[ "$BUS_TYPE" == "nvme" ]]; then + echo "Detecting in 15 seconds..." + sleep 10 + echo 1 > /sys/bus/pci/rescan + sleep 5 + + if [ ! -e "$DEVICE" ]; then + echo "Rebooting in 3 seconds. If still not detected, NVMe is DOA." + sleep 3 + reboot + else + echo "NVMe detected!" + fi + elif [[ "$BUS_TYPE" == "sata" && "$MEDIA_TYPE" == "ssd" ]]; then + echo "Detecting in 15 seconds..." + fi + + init-log +} + +run-wipe() { + # Safety check + if [[ "$DEVICE" == "$EXCLUDE_DEVICE" ]] || grep -q "$DEVICE" /proc/mounts; then + echo "CRITICAL ERROR: Attempted to wipe protected or mounted device: $DEVICE" + exit 1 + fi + + case "$BUS_TYPE:$MEDIA_TYPE" in + nvme:ssd) wipe-nvme ;; + sata:ssd) wipe-sata-ssd ;; + *:hdd) wipe-hdd ;; + *:emmc) wipe-emmc ;; + *:usb) wipe-usb ;; + *) echo "Unsupported configuration: $BUS_TYPE/$MEDIA_TYPE"; exit 1 ;; + esac +} + +configure-wipe() { + # 1. Select Bus Type + BUS_TYPE=$(dialog --title "Bus Type" --menu "Select bus type:" 15 60 4 \ + "nvme" "NVMe Drive" \ + "sata" "SATA Drive" \ + "usb" "USB Storage" 3>&1 1>&2 2>&3) || exit + + # 2. Select Media Type + MEDIA_TYPE=$(dialog --title "Media Type" --menu "Select media type:" 15 60 4 \ + "ssd" "Solid State Drive" \ + "hdd" "Hard Disk Drive" \ + "emmc" "eMMC Flash" 3>&1 1>&2 2>&3) || exit + + # 3. Select Device (Dynamic list of block devices) + local dev_list=() + while read -r dev; do + dev_list+=("$dev" "Available device") + done < <(lsblk -dpno NAME | grep -v "$EXCLUDE_DEVICE") + + if [ "${#dev_list[@]}" -eq 0 ]; then + dialog --msgbox "No available drives detected." 8 40 + clear + exit 1 + fi + + DEVICE=$(dialog --title "Device Selection" --menu "Select device to wipe:" 15 60 10 \ + "${dev_list[@]}" 3>&1 1>&2 2>&3) || exit + + # 4. Save to Config + mkdir -p "$(dirname "$CONFIG_FILE")" + echo " +BUS_TYPE=$BUS_TYPE +MEDIA_TYPE=$MEDIA_TYPE +DEVICE=$DEVICE + " > "$CONFIG_FILE" + + dialog --msgbox "Configuration saved to $CONFIG_FILE" 8 40 + clear + exit 0 +} + +main() { + local GETOPT_BIN="/run/current-system/sw/bin/getopt" + [ -f "$CONFIG_FILE" ] && source "$CONFIG_FILE" + + local OPTS + OPTS=$("$GETOPT_BIN" -o b:m:d:hc -l bus-type:,media-type:,device:,help,configure -- "$@") + if [ $? -ne 0 ]; then help; exit 1; fi + eval set -- "$OPTS" + + while true; do + case "$1" in + -b|--bus-type) BUS_TYPE="$2"; shift 2 ;; + -m|--media-type) MEDIA_TYPE="$2"; shift 2 ;; + -d|--device) DEVICE="$2"; shift 2 ;; + -h|--help) show-help ;; + -c|--configure) configure-wipe ;; + --) shift; break ;; + *) echo "Unexpected error"; help; exit 1 ;; + esac + done + + if [[ -z "$DEVICE" ]]; then + echo "Error: No device specified. Use -d or run -c to configure." + exit 1 + fi + init-log + detect-device + run-wipe +} + +main "$@" diff --git a/wipe2.sh b/wipe2.sh new file mode 100755 index 0000000..bed9d42 --- /dev/null +++ b/wipe2.sh @@ -0,0 +1,98 @@ +#!/bin/bash + +# Configuration +REPORT_DIR="/var/log/nwipe_reports" +WIPE_METHOD="dod3pass" +PYTHON_MAP_SCRIPT="/usr/local/bin/drive_map" + +mkdir -p "$REPORT_DIR" + +# ANSI Escape codes for colored text +GREEN='\033[0;32m' +CYAN='\033[0;36m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +clear +echo -e "${CYAN}=====================================================${NC}" +echo -e "${CYAN} NWIPE MULTI-DRIVE CONTROL PANEL ${NC}" +echo -e "${CYAN}=====================================================${NC}" + +# 1. Print the visual layout map to the terminal first +if [ -f "$PYTHON_MAP_SCRIPT" ]; then + python3 "$PYTHON_MAP_SCRIPT" +else + echo "Warning: Python mapping script not found at $PYTHON_MAP_SCRIPT" +fi + +# 2. Safely isolate the boot/OS disk +OS_DISK=$(lsblk -no PKNAME $(findmnt -no SOURCE /)) +DRIVES=$(lsblk -dno NAME,TYPE | awk '$2=="disk" {print $1}') + +# Associative arrays to track state +declare -A DRIVE_BAYS +declare -A DEPLOYED_DRIVES + +echo -e "${YELLOW}Initializing independent background wipe tasks...${NC}" + +for DISK in $DRIVES; do + if [ "$DISK" = "$OS_DISK" ]; then + continue + fi + + # Fetch 1-indexed physical bay (e.g., R1-C3) + BAY_LOC=$(python3 "$PYTHON_MAP_SCRIPT" --mapping | grep "^${DISK}:" | cut -d':' -f2) + if [ -z "$BAY_LOC" ]; then + BAY_LOC="Unknown" + fi + + # Store bay mapping for reporting + DRIVE_BAYS[$DISK]=$BAY_LOC + + # Unique name for this drive's hidden tmux session + SESSION_NAME="hidden-wipe-${DISK}" + + # Force kill any stale sessions for this disk if they exist + tmux kill-session -t "$SESSION_NAME" 2>/dev/null + + # Command to run nwipe + NWIPE_CMD="sudo nwipe --autonuke --nowait --method=$WIPE_METHOD --PDFreportpath=$REPORT_DIR /dev/$DISK" + + # Spawn the nwipe task completely hidden inside a detached tmux session + tmux new-session -d -s "$SESSION_NAME" "$NWIPE_CMD" + + # Track that this drive is actively running + DEPLOYED_DRIVES[$DISK]="RUNNING" + + echo " -> Drive /dev/$DISK ($BAY_LOC) started in background." +done + +echo -e "\n${YELLOW}Monitoring drive progress. Do not close this terminal.${NC}" +echo -e "-----------------------------------------------------\n" + +# 3. Live Monitoring Loop +while [ ${#DEPLOYED_DRIVES[@]} -gt 0 ]; do + sleep 3 # Check status every 3 seconds + + for DISK in "${!DEPLOYED_DRIVES[@]}"; do + SESSION_NAME="hidden-wipe-${DISK}" + BAY=${DRIVE_BAYS[$DISK]} + + # Check if the background tmux session has died (meaning nwipe finished) + if ! tmux has-session -t "$SESSION_NAME" 2>/dev/null; then + # Format the output to fit your non-programmer technician layout + # Translates internal R1-C1 to user friendly R1:C1 format + DISPLAY_BAY=$(echo "$BAY" | sed 's/-/:/') + + echo -e "${GREEN}[SUCCESS] Drive $DISPLAY_BAY [/dev/$DISK] wiped successfully. PDF certificate generated.${NC}" + + # Remove from tracking list so we stop monitoring it + unset DEPLOYED_DRIVES[$DISK] + fi + done +done + +echo -e "\n${CYAN}=====================================================${NC}" +echo -e "${GREEN}ALL ACTIVE WIPING TASKS COMPLETED SUCCESSFULLY!${NC}" +echo -e "${CYAN}=====================================================${NC}\n" +echo -e "${YELLOW}Run xfrlogs when ready to transfer logs to USB.${NC}"