From 7f6792d6e3201f218f7721514f19e757a5a69729 Mon Sep 17 00:00:00 2001 From: Keith Nash Date: Mon, 5 Oct 2020 23:41:41 -0500 Subject: [PATCH] Fixed problem identifying some mechanical drives as SSDs Added -x option to control the badblocks -e option, allowing extended testing. Added smartctl to the list of dependencies. Changed disk type detection so that we assume all drives are mechanical drives unless they explicitly return 'Solid State Drive' for Rotational Rate. Removed datestamp from every line of log output, only emitting it in log headers. Minor reformatting. --- disk-burnin.sh | 124 +++++++++++++++++++++++++++++-------------------- 1 file changed, 73 insertions(+), 51 deletions(-) diff --git a/disk-burnin.sh b/disk-burnin.sh index 9cde881..0c49291 100755 --- a/disk-burnin.sh +++ b/disk-burnin.sh @@ -1,10 +1,35 @@ #!/bin/sh +################################################################################ +# +# disk-burnin.sh +# +################################################################################ + +################################################################################ +# PRE-EXECUTION VALIDATION +################################################################################ + +# Check if running as root +if [ "$(id -u)" -ne 0 ]; then + echo "ERROR: Must be run as root" >&2 + exit 2 +fi + +# Check required dependencies +readonly DEPENDENCIES="awk badblocks grep sed sleep smartctl" +for dependency in ${DEPENDENCIES}; do + if ! command -v "${dependency}" > /dev/null 2>&1; then + echo "ERROR: Command '${dependency}' not found" >&2 + exit 2 + fi +done + readonly USAGE=\ "NAME $(basename "$0") -- disk burn-in program SYNOPSIS - $(basename "$0") [-h] [-e] [-f] [-o ] + $(basename "$0") [-h] [-e] [-f] [-o ] [-x] DESCRIPTION A script to simplify the process of burning-in disks. Only intended for use @@ -19,12 +44,13 @@ DESCRIPTION In order to perform tests on drives, you will need to provide the -f option. OPTIONS - -h show help text - -e show extended help text - -f run in destructive, non-dry mode + -h Show help text + -e Show extended help text + -f Force script to run in destructive mode ALL DATA ON THE DISK WILL BE LOST! - -o write log files to (default: $(pwd)) - disk to burn-in (/dev/ may be omitted) + -o Write log files to (default: $(pwd)) + -x Run full pass of badblocks instead of exiting on first error + Disk to burn-in (/dev/ may be omitted) EXAMPLES $(basename "$0") sda @@ -184,14 +210,21 @@ VERSIONS Check for root privileges during runtime. Add option parsing, most notably (-h)elp and -f for non-dry-run mode. Add dry_run_wrapper() function. - Add disk type detection to skip badblocks for non-mechanical drives." + Add disk type detection to skip badblocks for non-mechanical drives. -################################################################################ -# PRE-EXECUTION VALIDATION -################################################################################ + KN, 5 Oct 2020 + Added -x option to control the badblocks -e option, allowing extended testing. + Added smartctl to the list of dependencies. + Changed disk type detection so that we assume all drives are mechanical drives + unless they explicitly return 'Solid State Drive' for Rotational Rate. + Removed datestamp from every line of log output, only emitting it in log headers. + Minor reformatting." + +# badblocks default -e option is 1, stop testing if a single error occurs +BB_E_ARG=1 # parse options -while getopts ':hefo:' option; do +while getopts ':hefo:x' option; do case "${option}" in h) echo "${USAGE}" exit @@ -204,6 +237,8 @@ while getopts ':hefo:' option; do ;; o) LOG_DIR="${OPTARG}" ;; + x) BB_E_ARG=0 + ;; :) printf 'Missing argument for -%s\n' "${OPTARG}" >&2 echo "${USAGE}" >&2 exit 2 @@ -217,30 +252,17 @@ done shift $(( OPTIND - 1 )) if [ -z "$1" ]; then - echo "Missing option: " >&2 + echo "ERROR: Missing disk argument" >&2 echo "${USAGE}" >&2 exit 2 fi -# Check required dependencies -readonly DEPENDENCIES="awk badblocks grep sed sleep" -for dependency in ${DEPENDENCIES}; do - if ! command -v "${dependency}" > /dev/null 2>&1; then - echo "Command '${dependency}' not found" >&2 - exit 2 - fi -done - -# Check if running as root -if [ "$(id -u)" -ne 0 ]; then - echo "Please run as root" >&2 - exit 2 -fi - ################################################################################ # CONSTANTS ################################################################################ +readonly BB_E_ARG + # Drive to burn-in DRIVE="$1" # prepend /dev/ if necessary @@ -249,6 +271,12 @@ if ! printf '%s' "${DRIVE}" | grep "/dev/\w*" > /dev/null 2>&1; then fi readonly DRIVE +if [ ! -e "$DRIVE" ]; then + echo "ERROR: Disk does not exist: $DRIVE" >&2 + echo "${USAGE}" >&2 + exit 2 +fi + # Set to working directory if -o wasn't provided [ -z "${LOG_DIR}" ] && LOG_DIR="$(pwd)" # Trim trailing slashes @@ -314,12 +342,11 @@ DISK_MODEL="$(get_smart_info_value "Device Model")" [ -z "${DISK_MODEL}" ] && DISK_MODEL="$(get_smart_info_value "Model Number")" readonly DISK_MODEL -# Get disk type +# Get disk type; unless we get 'Solid State Device' as return value, assume +# we have a mechanical drive. DISK_TYPE="$(get_smart_info_value "Rotation Rate")" -if printf '%s' "${DISK_TYPE}" | grep "rpm" > /dev/null 2>&1; then - DISK_TYPE="mechanical" -else - DISK_TYPE="non-mechanical" +if printf '%s' "${DISK_TYPE}" | grep -i "solid_state_device" > /dev/null 2>&1; then + DISK_TYPE="SSD" fi readonly DISK_TYPE @@ -358,10 +385,10 @@ readonly BB_File="${LOG_DIR}/burnin-${DISK_MODEL}_${SERIAL_NUMBER}.bb" # Outputs: # Write message to stdout and log file. ################################################## -log_info() -{ - now="$(date +"%F %T %Z")" - printf "%s\n" "[${now}] $1" | tee -a "${LOG_FILE}" +log_info() { +# now="$(date +"%F %T %Z")" +# printf "%s\n" "[${now}] $1" | tee -a "${LOG_FILE}" + printf "%s\n" "$1" | tee -a "${LOG_FILE}" } ################################################## @@ -369,10 +396,9 @@ log_info() # Arguments: # Message to log. ################################################## -log_header() -{ +log_header() { log_info "+-----------------------------------------------------------------------------" - log_info "+ $1" + log_info "+ $1: $(date)" log_info "+-----------------------------------------------------------------------------" } @@ -422,8 +448,7 @@ cleanup_log() { # Arguments: # Command to run. ################################################## -dry_run_wrapper() -{ +dry_run_wrapper() { if [ -z "$DRY_RUN" ]; then log_info "DRY RUN: $*" return 0 @@ -451,7 +476,7 @@ dry_run_wrapper() ################################################## log_runtime_info() { log_info "Host: ${HOSTNAME}" - log_info "OS Flavor: ${OS_FLAVOR}" + log_info "OS: ${OS_FLAVOR}" log_info "Drive: ${DRIVE}" log_info "Disk Type: ${DISK_TYPE}" log_info "Drive Model: ${DISK_MODEL}" @@ -476,8 +501,7 @@ log_runtime_info() { # 0 if success or failure. # 1 if timeout threshold exceeded. ################################################## -poll_selftest_complete() -{ +poll_selftest_complete() { l_poll_duration_seconds=0 while [ "${l_poll_duration_seconds}" -lt "${POLL_TIMEOUT_SECONDS}" ]; do smartctl --all "${DRIVE}" \ @@ -512,8 +536,7 @@ poll_selftest_complete() # - long # Test duration in seconds. ################################################## -run_smart_test() -{ +run_smart_test() { log_header "Running SMART $1 test" dry_run_wrapper "smartctl --test=\"$1\" \"${DRIVE}\"" log_info "SMART $1 test started, awaiting completion for $2 seconds ..." @@ -533,11 +556,10 @@ run_smart_test() # Arguments: # None ################################################## -run_badblocks_test() -{ +run_badblocks_test() { log_header "Running badblocks test" - if [ "${DISK_TYPE}" = "mechanical" ]; then - dry_run_wrapper "badblocks -b 4096 -wsv -e 1 -o \"${BB_File}\" \"${DRIVE}\"" + if [ "${DISK_TYPE}" != "SSD" ]; then + dry_run_wrapper "badblocks -b 4096 -wsv -e ${BB_E_ARG} -o \"${BB_File}\" \"${DRIVE}\"" else log_info "SKIPPED: badblocks for ${DISK_TYPE} device" fi @@ -553,7 +575,7 @@ run_badblocks_test() # None ################################################## log_full_device_info() { - log_header "SMART and non-SMART information" + log_header "Drive information" dry_run_wrapper "smartctl --xall --vendorattribute=7,hex48 \"${DRIVE}\" | tee -a \"${LOG_FILE}\"" }