Last active
August 24, 2023 08:26
-
-
Save noelruault/cf65e0e586f14f74f2bb3194042e267a to your computer and use it in GitHub Desktop.
Script that helps to erase a disk content using `hdparm` and then copies a designated source disk (or `/dev/null`) into a specified target disk.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
#================================================================ | |
# HEADER | |
#================================================================ | |
#% SYNOPSIS | |
#+ ${SCRIPT_NAME} [-hv] args ... | |
#% | |
#% DESCRIPTION | |
#% This is a script that erases a disk and then copies a designated source disk into an specified target disk. | |
#% You can run it in one line when connected to the internet like this: | |
#% wget -qO - http://link/to/raw/wipedisk.sh | bash | |
#% | |
#% | |
#% OPTIONS | |
#% -t, --timelog Add timestamp to log ("+%y/%m/%d@%H:%M:%S") | |
#% -h, --help Print this help | |
#% -v, --version Print script information | |
#% | |
#% EXAMPLES | |
#% ${SCRIPT_NAME} -o DEFAULT arg1 arg2 | |
#% | |
#================================================================ | |
#- IMPLEMENTATION | |
#- version ${SCRIPT_NAME} | |
#- author Noël RUAULT | |
#- copyright Copyright (c) (www.noel.engineer) | |
#- license GNU General Public License | |
#- | |
#================================================================ | |
# HISTORY | |
# 2023/04/01 : noelruault : Script creation | |
# | |
#================================================================ | |
# DEBUG OPTION | |
# set -n # Uncomment to check your syntax, without execution. | |
# set -x # Uncomment to debug this shell script | |
# | |
#================================================================ | |
# END_OF_HEADER | |
#================================================================ | |
#== ==# | |
SCRIPT_HEADSIZE=$(head -200 ${0} | grep -n "^# END_OF_HEADER" | cut -f1 -d:) | |
SCRIPT_NAME="$(basename ${0})" | |
MAIN_COLOR="#04B575" | |
#== ==# | |
usage() { | |
printf "Usage: " | |
head -${SCRIPT_HEADSIZE:-99} ${0} | grep -e "^#+" | sed -e "s/^#+[ ]*//g" -e "s/\${SCRIPT_NAME}/${SCRIPT_NAME}/g" | |
} | |
usagefull() { head -${SCRIPT_HEADSIZE:-99} ${0} | grep -e "^#[%+-]" | sed -e "s/^#[%+-]//g" -e "s/\${SCRIPT_NAME}/${SCRIPT_NAME}/g"; } | |
scriptinfo() { head -${SCRIPT_HEADSIZE:-99} ${0} | grep -e "^#-" | sed -e "s/^#-//g" -e "s/\${SCRIPT_NAME}/${SCRIPT_NAME}/g"; } | |
trap "exit" INT | |
if [ "$(id -u)" -ne 0 ]; then | |
echo 'This script must be run by root' >&2 | |
exit 1 | |
fi | |
## dependencies will install all the additional software required to run this script | |
dependencies() { | |
if command -v gum &>/dev/null; then return; fi # All good, exit gracefully | |
case $1 in | |
darwin) | |
yes | brew install gum | |
;; | |
linux) | |
mkdir -p /etc/apt/keyrings | |
wget -qO - https://repo.charm.sh/apt/gpg.key | gpg --dearmor -o /etc/apt/keyrings/charm.gpg | |
# curl -fsSL https://repo.charm.sh/apt/gpg.key | gpg --dearmor -o /etc/apt/keyrings/charm.gpg | |
echo "deb [signed-by=/etc/apt/keyrings/charm.gpg] https://repo.charm.sh/apt/ * *" | tee /etc/apt/sources.list.d/charm.list | |
apt update && apt -y install gum | |
;; | |
*) | |
echo "$0: error: unrecognized operating system $1" | |
echo "$0: $scriptinfo" | |
exit 0 | |
;; | |
esac | |
} | |
wipe() { | |
gum confirm "Wipe all data from $DST?" && | |
hdparm --user-master user --security-set-pass pass $1 && | |
hdparm --user-master user --security-erase-enhanced pass $1 | |
} | |
## copy receives two parameters $1=source and $2=destination and copies src into dst | |
copy() { | |
gum confirm "Copy content from $1 to $2 ?" && | |
dd if=$1 of=$2 bs=8M status=progress | |
} | |
## is_frozen returns true if a disk is in a frozen state, false otherwise | |
is_frozen() { | |
diskstate=$(hdparm -I $1 | grep frozen | xargs | sed 's/ //g') | |
case $diskstate in | |
notfrozen) | |
return 1 # 1 = false | |
;; | |
frozen) | |
return 0 # 0 = true | |
;; | |
*) | |
echo "error: couldn't find disk state" | |
return 0 # 0 = true | |
;; | |
esac | |
} | |
## disks sets SSDOPTS and VERBOSESSDOPTS, as well as SRC and DST | |
## - SSDOPTS: The available list of disks attached to the computer | |
## - VERBOSESSDOPTS: The verbose list of disks attached to the computer | |
## - SRC: The source disk | |
## - DST: The destination disk | |
disks() { | |
case $1 in | |
darwin) | |
SSDOPTS=($(diskutil list | grep physical | egrep -o '^[^(]+')) | |
SSDOPTS+=("/dev/zero") | |
VERBOSESSDOPTS=$(diskutil list) | |
;; | |
linux) | |
SSDOPTS=($(lsblk -I 8 -nd --output PATH)) | |
SSDOPTS+=("/dev/zero") | |
VERBOSESSDOPTS=$(lsblk -I 8 -nd --output PATH,SIZE,TYPE) | |
;; | |
*) | |
echo "$0: error: unrecognized operating system $1" | |
echo "$0: $scriptinfo" | |
exit 0 | |
;; | |
esac | |
if ((${#SSDOPTS[@]} < 2)); then | |
echo "error: not enough disks" | |
exit 1 | |
fi | |
echo "Disks detected:" | |
gum style --padding '1 2' --border double --border-foreground $MAIN_COLOR "${VERBOSESSDOPTS[*]}" | |
echo "Select $(gum style --foreground $MAIN_COLOR "source disk") from the list above" | |
sleep 1 | |
SRC=$(gum choose ${SSDOPTS[@]}) | |
echo "Select $(gum style --foreground $MAIN_COLOR "destination disk") from the list above" | |
sleep 1 | |
DST=$(gum choose ${SSDOPTS[@]}) | |
if [ "$SRC" = "$DST" ]; then | |
echo "error: disks selected match" | |
exit 1 | |
fi | |
} | |
## Returns the current operating system in lowercase using 'uname -a' | |
os(){ | |
current_operating_system="$(uname -a | awk '{print $1}' | tr '[:upper:]' '[:lower:]')" | |
if [ -z "$current_operating_system" ]; then | |
echo "\$CURRENT_OS couldn't be found" | |
exit 1 | |
else | |
echo "$current_operating_system" | |
fi | |
} | |
freeze(){ | |
# NOTE: The computer can respond "write error: Device or resource busy". This usually goes away after waiting a few seconds (10-30 sec), so just try again after a while. | |
gum confirm "Target disk is frozen, the system is about to hibernate to force the disks to an unfrozen state" && echo -n mem >/sys/power/state # rtcwake -m mem -s 10 | |
if is_frozen "$DST"; then echo "couldn't unfreeze disk" && exit 1; fi | |
} | |
main(){ | |
CURRENT_OS=$(os) | |
dependencies "$CURRENT_OS" | |
disks "$CURRENT_OS" | |
is_frozen "$DST" && freeze | |
wipe $DST | |
copy $SRC $DST | |
} | |
main |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment