fix: harden mtm-ddwipe confirmation and wipe flow

Add strict shell options, root and block-device validation, and a typed-device confirmation prompt before wiping. Preserve the fallback wipe sequence through secure discard, zero discard, and dd, while tightening error handling and keeping messages concise.
This commit is contained in:
2026-04-27 23:32:45 +02:00
parent 7011426381
commit ecc6e5b038
2 changed files with 122 additions and 75 deletions
+13 -12
View File
@@ -4,25 +4,26 @@ description: mtm-ddwipe project conventions
# Project conventions # Project conventions
- Use English throughout the project. - Use English throughout the project.
- Keep shell scripts Bash-based when Bash is already used by the project. - Keep shell scripts Bash-based.
- Preserve the current behavior of the main script: - Preserve the current behavior of the main script: `mtm-ddwipe` wipes block devices.
- `mtm-ddwipe`: wipe devices. - Strengthen destructive-action safety checks in `mtm-ddwipe`.
- Strengthen destructive-action safety checks in `mtm-ddwipe` when making changes. - Keep `mtm-ddwipe` interactive by default.
- Keep `mtm-ddwipe` interactive by default unless a change explicitly adds a safe opt-in flag. - Require explicit confirmation before destructive actions.
- Keep user-facing messages short, clear, and in English. - Keep user-facing messages short and clear.
- Prefer minimal, focused changes that do not alter the intent of the existing scripts, unless the script behavior is intentionally updated. - Keep error and help messages short and clear.
- Maintain `.continue/rules/project.md` whenever project conventions or script behavior change. - Prefer minimal, focused changes that preserve intent.
- Keep `.continue/rules/project.md` aligned with project conventions and concise.
- `mtm-ddwipe` is a small Bash script with helper functions. - `mtm-ddwipe` is a small Bash script with helper functions.
- Keep the host and line-number removal behavior intact. - Keep the host and line-number removal behavior intact for related output processing.
- `mtm-ddwipe` must print a usage line and support `-h`/`--help`. - `mtm-ddwipe` must print a usage line and support `-h`/`--help`.
- Validate that wipe targets are real block devices before operating on them. - Validate that wipe targets are real block devices before operating on them.
- Keep short, explicit confirmation prompts before destructive operations. - Keep short, explicit confirmation prompts before destructive operations.
- Keep error and help messages short, clear, and in English. - Prefer confirmation prompts that require typing the target device path.
- Keep help text concise and usage-first. - Keep help text concise and usage-first.
- When changing `mtm-ddwipe`, keep destructive safeguards strict and explicit. - Keep destructive safeguards strict and explicit.
- If adding non-interactive support, make it an opt-in safety flag. - If adding non-interactive support, make it an opt-in safety flag.
- Keep device identification prompts clear and specific. - Keep device identification prompts clear and specific.
- Preserve the fallback wipe flow unless the change is intentionally about wiping behavior. - Preserve the fallback wipe flow: secure discard, zero discard, then zero-fill with `dd`.
# Project identity # Project identity
- Main script: `mtm-ddwipe` - Main script: `mtm-ddwipe`
+109 -63
View File
@@ -1,108 +1,154 @@
#!/bin/bash #!/bin/bash
set -euo pipefail
IFS=$'\n\t'
VERSION="0.0.3" VERSION="0.0.3"
STARTDATE="" STARTDATE=0
STARTDATESTRING="" STARTDATESTRING=""
DEVICE_PATH=""
show_help() { usage() {
echo "Usage: mtm-ddwipe DEVICE" cat <<EOF
echo "Wipe a block device." Usage: mtm-ddwipe-2 DEVICE
echo "Version: ${VERSION}" Wipe a block device.
Version: ${VERSION}
EOF
}
log() {
echo "$*"
}
die() {
echo "Error: $*" >&2
exit 1
} }
check_args() { check_args() {
case "${1}" in if [ $# -ne 1 ]; then
usage
exit 1
fi
case "$1" in
-h|--help) -h|--help)
show_help usage
exit 0 exit 0
;; ;;
"")
show_help
exit 1
;;
-*) -*)
echo "Invalid option." die "Invalid option."
show_help
exit 1
;; ;;
esac esac
} }
check_dev_exist() { check_device() {
if [ ! -e "${1}" ]; then local dev="$1"
echo "Missing device."
exit 1
fi
}
check_dev_block() { [ -e "$dev" ] || die "Missing device: $dev"
if [ ! -b "${1}" ]; then [ -b "$dev" ] || die "Not a block device: $dev"
echo "Not a block device."
exit 1
fi
} }
confirm_wipe() { confirm_wipe() {
lsblk "${1}" local dev="$1"
local choice=""
lsblk "$dev"
echo "" echo ""
read -r -p "Wipe ${1} (y/[n])? " CHOICE read -r -p "Type the device path to confirm wipe: " choice
case "${CHOICE}" in [ "$choice" = "$dev" ] || die "Canceled"
y|Y) echo ""
echo "" }
;;
*) confirm_root() {
echo "Canceled" if [ "${EUID:-$(id -u)}" -ne 0 ]; then
exit 1 die "This tool must be run as root."
;; fi
esac
} }
print_time() { print_time() {
local enddate calctime
echo "" echo ""
echo "Start date :" echo "Start date :"
echo "${STARTDATESTRING}" echo "$STARTDATESTRING"
ENDDATE=$(date +%s) enddate=$(date +%s)
echo "" echo ""
echo "End date :" echo "End date :"
date date
CALCTIME=$((ENDDATE-STARTDATE)) calctime=$((enddate - STARTDATE))
echo "" echo ""
echo "Total time :" echo "Total time :"
date -d@${CALCTIME} -u +%H:%M:%S date -d@"${calctime}" -u +%H:%M:%S
}
wipe_with_blkdiscard_secure() {
local dev="$1"
log "blkdiscard secure"
blkdiscard -f -p 500M -s -v "$dev"
}
wipe_with_blkdiscard_zero() {
local dev="$1"
log "blkdiscard zero"
blkdiscard -f -p 500M -z -v "$dev"
}
wipe_with_dd() {
local dev="$1"
log "dd zero"
dd if=/dev/zero of="$dev" bs=1M status=progress conv=fsync
log "Wiped with dd, check if full size is written."
log "Otherwise use a mechanical destruction of the device."
} }
wipe_dev() { wipe_dev() {
local dev="$1"
STARTDATE=$(date +%s) STARTDATE=$(date +%s)
STARTDATESTRING="$(date)" STARTDATESTRING="$(date)"
echo "Begin wiping device ${1}" DEVICE_PATH="$dev"
log "Begin wiping device $dev"
echo "" echo ""
echo "Start date :" log "Start date :"
echo "${STARTDATESTRING}" log "$STARTDATESTRING"
echo "" echo ""
echo "blkdiscard secure"
if ! blkdiscard -f -p 500M -s -v "${1}"; then if wipe_with_blkdiscard_secure "$dev"; then
echo "" echo ""
echo "blkdiscard zero" log "Device $dev wiped."
if ! blkdiscard -f -p 500M -z -v "${1}"; then return
echo ""
echo "dd zero"
if ! dd if=/dev/zero of="${1}" bs=1M status=progress; then
echo "Wiped with dd, check if full size is writed."
echo "Otherwise use a mechanical destruction of the device."
print_time
exit 1
fi
fi
fi fi
echo "" echo ""
echo "Device ${1} wiped." if wipe_with_blkdiscard_zero "$dev"; then
echo ""
log "Device $dev wiped."
return
fi
echo ""
if wipe_with_dd "$dev"; then
echo ""
log "Device $dev wiped."
return
fi
die "Wipe failed. The device may not be fully overwritten."
} }
check_args "${1}" main() {
check_dev_exist "${1}" check_args "$@"
check_dev_block "${1}" confirm_root
confirm_wipe "${1}" check_device "$1"
wipe_dev "${1}" confirm_wipe "$1"
print_time wipe_dev "$1"
print_time
}
main "$@"