Add HDD device previews and root guards

This commit is contained in:
dido committed 2026-09-29 09:08:57 +03:00
1 parent 33c4229848
commit cf53a6bb50
5 files changed
+52 -16

No files matched your search

+3 -1
View File
@@ -20,7 +20,9 @@ Erase, Overwrite. За ATA избира Enhanced Security Erase, ако устр
потвърждения, като второто е точното име на устройството. потвърждения, като второто е точното име на устройството.
**Изтриването е необратимо и при режим за цял диск засяга всички дялове.** **Изтриването е необратимо и при режим за цял диск засяга всички дялове.**
В началото скриптът предупреждава, че работата може да продължи часове, и Преди въпросите за потвърждение скриптът показва наличните block devices,
размер, тип, файлов тип и mount points; подаденото устройство е оцветено в
червено в терминал. След това скриптът предупреждава, че работата може да продължи часове, и
изисква `yes` за продължаване или `no` за прекратяване. Не изключвай, изисква `yes` за продължаване или `no` за прекратяване. Не изключвай,
рестартирай или приспивай компютъра и не прекъсвай захранването или връзката рестартирай или приспивай компютъра и не прекъсвай захранването или връзката
с диска. За дял следва отделно потвърждение с точния device path; за цял диск с диска. За дял следва отделно потвърждение с точния device path; за цял диск
+12 -5
View File
@@ -9,12 +9,19 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=lib/common.sh # shellcheck source=lib/common.sh
source "${SCRIPT_DIR}/../lib/common.sh" source "${SCRIPT_DIR}/../lib/common.sh"
if [[ "$EUID" -ne 0 ]]; then
common::log "WARNING: This script must be run as root (for example, with sudo)."
common::die "stopping before processing arguments or checking dependencies"
fi
SCRIPT_HELP=$(cat <<'HELP' SCRIPT_HELP=$(cat <<'HELP'
Usage: sudo ./HDD/erase-storage.sh DEVICE [zero|random] Usage: sudo ./HDD/erase-storage.sh DEVICE [zero|random]
For a partition, writes one full pass of zeros (default) or pseudorandom data. For a partition, writes one full pass of zeros (default) or pseudorandom data.
For a whole disk, detects and runs a supported ATA Secure Erase or NVMe Sanitize For a whole disk, detects and runs a supported ATA Secure Erase or NVMe Sanitize
operation. Whole-disk erasure requires two separate confirmations. operation. Whole-disk erasure requires two separate confirmations.
Lists available block devices and mount points before continuing, highlighting
the selected device in red when run in a terminal.
At startup, asks you to confirm that you can keep the computer and drive At startup, asks you to confirm that you can keep the computer and drive
powered and connected for the hours the operation may take. powered and connected for the hours the operation may take.
@@ -53,20 +60,17 @@ case "$FILL_MODE" in
;; ;;
esac esac
common::log "WARNING: Erasing data may take hours. Do not power off, reboot, or suspend the computer, or disconnect power or the drive." for required_command in awk findmnt lsblk readlink swapon date dd sleep; do
common::confirm "Can the computer and drive remain powered and connected until the operation finishes?" || exit 0
for required_command in findmnt lsblk readlink swapon date dd sleep; do
common::require_cmd "$required_command" common::require_cmd "$required_command"
done done
[[ "$EUID" -eq 0 ]] || common::die "this script must be run as root (for example, with sudo)"
[[ -b "$DEVICE_INPUT" ]] || common::die "$DEVICE_INPUT does not exist or is not a block device" [[ -b "$DEVICE_INPUT" ]] || common::die "$DEVICE_INPUT does not exist or is not a block device"
DEVICE="$(readlink -f -- "$DEVICE_INPUT")" || common::die "cannot resolve device path: $DEVICE_INPUT" DEVICE="$(readlink -f -- "$DEVICE_INPUT")" || common::die "cannot resolve device path: $DEVICE_INPUT"
DEVICE_TYPE="$(lsblk -dnro TYPE -- "$DEVICE")" || common::die "cannot determine device type" DEVICE_TYPE="$(lsblk -dnro TYPE -- "$DEVICE")" || common::die "cannot determine device type"
[[ "$DEVICE_TYPE" == "part" || "$DEVICE_TYPE" == "disk" ]] \ [[ "$DEVICE_TYPE" == "part" || "$DEVICE_TYPE" == "disk" ]] \
|| common::die "only a partition or a whole disk is accepted (detected: $DEVICE_TYPE)" || common::die "only a partition or a whole disk is accepted (detected: $DEVICE_TYPE)"
common::show_block_devices "$DEVICE" || common::die "cannot list available block devices"
ROOT_SOURCE="$(findmnt -n -o SOURCE /)" || common::die "cannot determine the root filesystem device" ROOT_SOURCE="$(findmnt -n -o SOURCE /)" || common::die "cannot determine the root filesystem device"
ROOT_SOURCE="${ROOT_SOURCE%%\[*}" ROOT_SOURCE="${ROOT_SOURCE%%\[*}"
@@ -117,6 +121,9 @@ while IFS= read -r child_device; do
done <<< "$ACTIVE_SWAP_DEVICES" done <<< "$ACTIVE_SWAP_DEVICES"
done <<< "$DEVICE_TREE" done <<< "$DEVICE_TREE"
common::log "WARNING: Erasing data may take hours. Do not power off, reboot, or suspend the computer, or disconnect power or the drive."
common::confirm "Can the computer and drive remain powered and connected until the operation finishes?" || exit 0
if [[ "$DEVICE_TYPE" == "part" ]]; then if [[ "$DEVICE_TYPE" == "part" ]]; then
[[ $# -eq 1 || "$FILL_MODE" == "zero" || "$FILL_MODE" == "random" ]] \ [[ $# -eq 1 || "$FILL_MODE" == "zero" || "$FILL_MODE" == "random" ]] \
|| common::die "invalid fill mode; use 'zero' or 'random'" || common::die "invalid fill mode; use 'zero' or 'random'"
+4 -2
View File
@@ -16,8 +16,10 @@
Ако дъщерно устройство не може да се демонтира, скриптът прекратява Ако дъщерно устройство не може да се демонтира, скриптът прекратява
операцията. операцията.
В началото скриптът предупреждава, че работата може да продължи часове, и В началото скриптът показва наличните block devices, размер, тип, файлов тип
изисква отговор `yes` за продължаване или `no` за прекратяване. По време на и mount points; подаденият диск е оцветен в червено в терминал. След това
предупреждава, че работата може да продължи часове, и изисква отговор `yes`
за продължаване или `no` за прекратяване. По време на
целия процес не изключвай компютъра, не го рестартирай/приспивай и не целия процес не изключвай компютъра, не го рестартирай/приспивай и не
прекъсвай захранването или връзката с диска. Преди самия запис има отделно прекъсвай захранването или връзката с диска. Преди самия запис има отделно
потвърждение с `YES`. потвърждение с `YES`.
+12 -8
View File
@@ -10,12 +10,19 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=lib/common.sh # shellcheck source=lib/common.sh
source "${SCRIPT_DIR}/../lib/common.sh" source "${SCRIPT_DIR}/../lib/common.sh"
if [[ "$EUID" -ne 0 ]]; then
common::log "WARNING: This script must be run as root (for example, with sudo)."
common::die "stopping before processing arguments or checking dependencies"
fi
SCRIPT_HELP=$(cat <<'HELP' SCRIPT_HELP=$(cat <<'HELP'
Usage: sudo ./HDD/repair-hdd.sh DEVICE [zero|null|random] Usage: sudo ./HDD/repair-hdd.sh DEVICE [zero|null|random]
Overwrites the selected disk, then runs a SMART extended self-test. This Overwrites the selected disk, then runs a SMART extended self-test. This
destroys all data on DEVICE. Use only with a directly connected SATA disk; destroys all data on DEVICE. Use only with a directly connected SATA disk;
USB adapters may require adding -d sat to the smartctl calls. USB adapters may require adding -d sat to the smartctl calls.
Lists available block devices and mount points before continuing, highlighting
the selected device in red when run in a terminal.
At startup, asks you to confirm that you can keep the computer and drive At startup, asks you to confirm that you can keep the computer and drive
powered and connected for the hours this operation may take. powered and connected for the hours this operation may take.
@@ -57,23 +64,17 @@ case "$FILL_MODE" in
;; ;;
esac esac
common::log "WARNING: This operation may take hours. Do not power off, reboot, or suspend the computer, or disconnect power or the drive." for required_command in awk findmnt lsblk readlink swapon mkdir date tee smartctl grep umount dd sync sleep head base64; do
common::confirm "Can the computer and drive remain powered and connected until this operation finishes?" || exit 0
for required_command in findmnt lsblk readlink swapon mkdir date tee smartctl grep umount dd sync sleep head base64; do
common::require_cmd "$required_command" common::require_cmd "$required_command"
done done
if [[ "$EUID" -ne 0 ]]; then
common::die "this script must be run as root (for example, with sudo)"
fi
if [[ ! -b "$DEVICE" ]]; then if [[ ! -b "$DEVICE" ]]; then
common::die "$DEVICE does not exist or is not a block device" common::die "$DEVICE does not exist or is not a block device"
fi fi
# Refuse the root filesystem device and any block device it depends on. # Refuse the root filesystem device and any block device it depends on.
TARGET_DEVICE="$(readlink -f -- "$DEVICE")" || common::die "cannot resolve device path: $DEVICE" TARGET_DEVICE="$(readlink -f -- "$DEVICE")" || common::die "cannot resolve device path: $DEVICE"
common::show_block_devices "$TARGET_DEVICE" || common::die "cannot list available block devices"
ROOT_SOURCE="$(findmnt -n -o SOURCE /)" || common::die "cannot determine the root filesystem device" ROOT_SOURCE="$(findmnt -n -o SOURCE /)" || common::die "cannot determine the root filesystem device"
ROOT_SOURCE="${ROOT_SOURCE%%\[*}" ROOT_SOURCE="${ROOT_SOURCE%%\[*}"
ROOT_DEVICE="$(readlink -f -- "$ROOT_SOURCE")" || common::die "cannot resolve root device path: $ROOT_SOURCE" ROOT_DEVICE="$(readlink -f -- "$ROOT_SOURCE")" || common::die "cannot resolve root device path: $ROOT_SOURCE"
@@ -100,6 +101,9 @@ while IFS= read -r child_device; do
done < <(swapon --show --noheadings --raw --output NAME) done < <(swapon --show --noheadings --raw --output NAME)
done <<< "$DEVICE_TREE" done <<< "$DEVICE_TREE"
common::log "WARNING: This operation may take hours. Do not power off, reboot, or suspend the computer, or disconnect power or the drive."
common::confirm "Can the computer and drive remain powered and connected until this operation finishes?" || exit 0
if [[ "$FILL_MODE" == "random" ]] && ! command -v openssl >/dev/null 2>&1; then if [[ "$FILL_MODE" == "random" ]] && ! command -v openssl >/dev/null 2>&1; then
common::log "OpenSSL is unavailable; random mode will use /dev/urandom." common::log "OpenSSL is unavailable; random mode will use /dev/urandom."
fi fi
+21
View File
@@ -90,3 +90,24 @@ common::require_cmd() {
common::die "required command '${cmd}' not found on PATH" common::die "required command '${cmd}' not found on PATH"
fi fi
} }
# common::show_block_devices prints available block devices and highlights
# the selected device when output is going to a terminal.
common::show_block_devices() {
local selected_device="$1"
local color=0
if [[ -t 1 && -z "${NO_COLOR:-}" ]]; then
color=1
fi
common::log "Available block devices and mount points (selected device highlighted):"
lsblk --list --paths --output PATH,SIZE,TYPE,FSTYPE,MOUNTPOINTS \
| awk -v selected="$selected_device" -v color="$color" '
NR > 1 && $1 == selected && color {
printf "\033[31m%s\033[0m\n", $0
next
}
{ print }
'
}