7 Commits

Author SHA1 Message Date
matmoul 55c55a4a08 feat: strengthen wipe safety checks and confirmation flow
Add mounted/in-use device detection, show detailed device info before confirmation, and require an exact wipe phrase to proceed. Also move status output to stderr and refresh the usage warnings for clearer destructive-action guidance.
2026-04-27 23:37:40 +02:00
matmoul ecc6e5b038 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.
2026-04-27 23:32:45 +02:00
matmoul 7011426381 docs: clarify mtm-ddwipe safety and prompt conventions 2026-04-27 23:20:07 +02:00
matmoul b01e72cba6 fix: improve mtm-ddwipe argument handling and timing output 2026-04-27 23:17:16 +02:00
matmoul 08d6ccde0d docs: tighten mtm-ddwipe help and project guidance 2026-04-27 23:05:22 +02:00
matmoul 7321d7e087 docs: update project rules for safer wipe behavior 2026-04-27 23:02:14 +02:00
matmoul 7609bf9c17 feat: improve release script with dry-run and version increments 2026-04-27 22:57:08 +02:00
3 changed files with 305 additions and 73 deletions
+33
View File
@@ -0,0 +1,33 @@
---
description: mtm-ddwipe project conventions
---
# Project conventions
- Use English throughout the project.
- Keep shell scripts Bash-based.
- Preserve the current behavior of the main script: `mtm-ddwipe` wipes block devices.
- Strengthen destructive-action safety checks in `mtm-ddwipe`.
- Keep `mtm-ddwipe` interactive by default.
- Require explicit confirmation before destructive actions.
- Show clear device details before confirmation.
- Check that target devices are not mounted or in use before wiping.
- Keep user-facing messages short and clear.
- Keep error and help messages short and clear.
- 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.
- Keep the host and line-number removal behavior intact for related output processing.
- `mtm-ddwipe` must print a usage line and support `-h`/`--help`.
- Validate that wipe targets are real block devices before operating on them.
- Keep short, explicit confirmation prompts before destructive operations.
- Prefer confirmation prompts that require typing the target device path or an exact safety phrase.
- Keep help text concise, usage-first, and warning-focused.
- Keep destructive safeguards strict and explicit.
- If adding non-interactive support, make it an opt-in safety flag.
- Keep device identification prompts clear and specific.
- Preserve the fallback wipe flow: secure discard, zero discard, then zero-fill with `dd`.
- Keep timing and status output short and readable.
# Project identity
- Main script: `mtm-ddwipe`
- License: GNU GPL v3
+112 -9
View File
@@ -1,32 +1,135 @@
#!/bin/bash
declare -r VERSION=${1}
declare -r MESSAGE=${2}
set -euo pipefail
declare -r TAGBRANCH=main
declare CURRENTBRANCH=""
declare ORIGBRANCH=""
declare -r ARG1="${1:-}"
declare -r ARG2="${2:-}"
declare is_dry_run=false
declare release_input=""
showHelp() {
echo makerelease version
cat <<'EOF'
Usage:
makerelease.sh VERSION
makerelease.sh +0.0.1
makerelease.sh +0.1
makerelease.sh +1
makerelease.sh --dry-run VERSION
makerelease.sh --dry-run +0.0.1
makerelease.sh --dry-run +0.1
makerelease.sh --dry-run +1
Creates an annotated Git tag from the current dev branch.
If VERSION starts with +, it is treated as an increment:
- +0.0.1 increments patch
- +0.1 increments minor
- +1 increments major
Use --dry-run to show the computed release version without running Git actions.
Requirements:
- run from a clean Git working tree
- current branch must be dev for real releases
- main branch must exist locally
EOF
}
if [ "${VERSION}" == "" ]; then
cleanup() {
if [ -n "${ORIGBRANCH}" ] && [ "${CURRENTBRANCH}" != "${ORIGBRANCH}" ]; then
git checkout "${ORIGBRANCH}" >/dev/null 2>&1 || true
fi
}
trap cleanup EXIT
if [ "${ARG1}" = "--dry-run" ] || [ "${ARG1}" = "-n" ]; then
is_dry_run=true
release_input="${ARG2:-}"
else
release_input="${ARG1}"
fi
if [ -z "${release_input}" ]; then
showHelp
echo ""
echo "no version provided!"
exit 1
fi
CURRENTBRANCH=$(git rev-parse --abbrev-ref HEAD)
if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
echo "You are not inside a Git repository!"
exit 1
fi
if [ ! "${CURRENTBRANCH}" == "dev" ]; then
if [ -n "$(git status --porcelain)" ]; then
echo "Working tree is not clean!"
echo "Commit or stash your changes before creating a release."
exit 1
fi
CURRENTBRANCH=$(git rev-parse --abbrev-ref HEAD)
ORIGBRANCH="${CURRENTBRANCH}"
if [ "${is_dry_run}" = false ] && [ "${CURRENTBRANCH}" != "dev" ]; then
echo "You are not in dev branch!"
echo "Use dev branch to make a release!"
exit 1
fi
release_tag="${release_input}"
if [ "${release_input}" != "${release_input#+}" ]; then
current_tag="$(git describe --tags --abbrev=0 2>/dev/null || true)"
if [ -z "${current_tag}" ]; then
echo "No existing tag found to increment from!"
exit 1
fi
case "${release_input}" in
+1)
release_tag="$(printf '%s' "${current_tag}" | awk -F. 'BEGIN{OFS="."} { $1+=1; $2=0; $3=0; print }')"
;;
+0.1)
release_tag="$(printf '%s' "${current_tag}" | awk -F. 'BEGIN{OFS="."} { $2+=1; $3=0; print }')"
;;
+0.0.1)
release_tag="$(printf '%s' "${current_tag}" | awk -F. 'BEGIN{OFS="."} { $3+=1; print }')"
;;
*)
echo "Unsupported increment syntax: ${release_input}"
exit 1
;;
esac
fi
if git rev-parse -q --verify "refs/tags/${release_tag}" >/dev/null; then
echo "Tag ${release_tag} already exists!"
exit 1
fi
if [ "${is_dry_run}" = true ]; then
echo "Dry run: computed release tag ${release_tag}"
exit 0
fi
echo "Release tag selected: ${release_tag}"
read -r -p "Proceed with release? [y/N] " confirm
case "${confirm}" in
y|Y)
;;
*)
echo "Release cancelled."
exit 1
;;
esac
git checkout "${TAGBRANCH}"
git merge "${CURRENTBRANCH}"
CURRENTBRANCH="${TAGBRANCH}"
git merge "${ORIGBRANCH}"
git push
git tag -a "${VERSION}" -m "${MESSAGE}"
git tag -a "${release_tag}" -m "Release ${release_tag}"
git push --tags
git checkout "${CURRENTBRANCH}"
echo "Created release tag ${release_tag}"
Executable → Regular
+158 -62
View File
@@ -1,89 +1,185 @@
#!/bin/bash
set -euo pipefail
IFS=$'\n\t'
declare -r DEV="${1}"
declare STARTDATE=""
declare STARTDATESTRING=""
VERSION="0.0.4"
STARTDATE=0
STARTDATESTRING=""
show_help() {
echo "ddwipe dev (/dev/sdX)"
echo ""
echo "Version : 0.0.3"
usage() {
cat <<EOF
Usage: mtm-ddwipe-2 DEVICE
Wipe a block device.
Warnings:
- This is destructive and irreversible.
- The target device must not be mounted or in use.
- blkdiscard support depends on the device and firmware.
- dd fallback may take a long time.
Version: ${VERSION}
EOF
}
log() {
echo "$*" >&2
}
die() {
echo "Error: $*" >&2
exit 1
}
check_args() {
if [ "${1}" == "" ]; then
show_help
if [ $# -ne 1 ]; then
usage
exit 1
fi
case "$1" in
-h|--help)
usage
exit 0
;;
-*)
die "Invalid option."
;;
esac
}
check_dev_exist() {
if [ ! -e "${1}" ]; then
echo "${1} is missing."
exit 1
check_device() {
local dev="$1"
[ -e "$dev" ] || die "Missing device: $dev"
[ -b "$dev" ] || die "Not a block device: $dev"
}
check_device_not_in_use() {
local dev="$1"
if lsblk -nrpo NAME,MOUNTPOINT "$dev" | awk '$2 != "" { found=1 } END { exit !found }'; then
die "Device or one of its children is mounted: $dev"
fi
}
confirm_wipe() {
lsblk "${1}"
local dev="$1"
local choice=""
echo "Selected device:"
lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINT,MODEL,SERIAL "$dev"
echo ""
echo "This will destroy data on: $dev"
echo "Type exactly: WIPE $dev"
echo ""
read -r -p "Confirmation: " choice
[ "$choice" = "WIPE $dev" ] || die "Canceled"
echo ""
read -r -p "Wipe ${1} (y/[n])?" CHOICE
case "${CHOICE}" in
y|Y ) echo "";;
* )
echo "Canceled"
exit 1
;;
esac
}
wipe_dev() {
STARTDATE=$(date +%s)
STARTDATESTRING="$(date)"
echo "Begin wiping device ${1}"
echo ""
echo "Start date :"
echo "${STARTDATESTRING}"
echo ""
echo "blkdiscard secure"
if ! blkdiscard -f -p 500M -s -v "${1}"; then
echo ""
echo "blkdiscard zero"
if ! blkdiscard -f -p 500M -z -v "${1}"; then
echo ""
echo "dd zero"
if ! dd if=/dev/zero of="${1}" bs=1M status=progress; then
# Need check if dd has all writed, if yes, return no error
# echo "Error wiping device ${1}, use phisical destroy !"
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
confirm_root() {
if [ "${EUID:-$(id -u)}" -ne 0 ]; then
die "This tool must be run as root."
fi
echo ""
echo "Device ${1} wipped !"
}
format_duration() {
local total="$1"
local hours minutes seconds
hours=$((total / 3600))
minutes=$(((total % 3600) / 60))
seconds=$((total % 60))
printf '%02d:%02d:%02d\n' "$hours" "$minutes" "$seconds"
}
print_time() {
echo ""
echo "Start date :"
echo "${STARTDATESTRING}"
local enddate calctime
ENDDATE=$(date +%s)
echo ""
echo "End date :"
date
log "Start date :"
log "$STARTDATESTRING"
enddate=$(date +%s)
calctime=$((enddate - STARTDATE))
CALCTIME=$((ENDDATE-STARTDATE))
echo ""
echo "Total time :"
date -d@${CALCTIME} -u +%H:%M:%S
log "End date :"
date >&2
echo ""
log "Total time :"
format_duration "$calctime" >&2
}
check_args "${DEV}"
check_dev_exist "${DEV}"
confirm_wipe "${DEV}"
wipe_dev "${DEV}"
print_time
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() {
local dev="$1"
STARTDATE=$(date +%s)
STARTDATESTRING="$(date)"
log "Begin wiping device $dev"
echo ""
log "Start date :"
log "$STARTDATESTRING"
echo ""
if wipe_with_blkdiscard_secure "$dev"; then
echo ""
log "Device $dev wiped."
return
fi
echo ""
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."
}
main() {
check_args "$@"
confirm_root
check_device "$1"
check_device_not_in_use "$1"
confirm_wipe "$1"
wipe_dev "$1"
print_time
}
main "$@"