Merge pull request #7 from schnerring/master
Remove code duplication and dependencies; improve portability, readability and docs; add option parsing, dependency and sudo check
This commit is contained in:
12
.editorconfig
Normal file
12
.editorconfig
Normal file
@@ -0,0 +1,12 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
32
README.md
32
README.md
@@ -1,8 +1,11 @@
|
||||
# Shell script for burn-in and testing of drives
|
||||
|
||||
## Purpose
|
||||
|
||||
`disk-burnin.sh` is a POSIX-compliant shell script I wrote to simplify the process of burning-in disks. It is intended for use only on disks which do not contain data, such as new disks or disks which are being tested or re-purposed. I was inspired by the ["How To: Hard Drive Burn-In Testing"](https://forums.freenas.org/index.php?threads/how-to-hard-drive-burn-in-testing.21451/) thread on the FreeNAS forum and I want to give full props to the good folks who contributed to that thread.
|
||||
|
||||
## Warnings
|
||||
|
||||
Be warned that:
|
||||
|
||||
* This script runs the `badblocks` program in destructive mode, which erases any data on the disk. Therefore, please be careful! __Do not run this script on disks containing data you value!__
|
||||
@@ -10,11 +13,12 @@ Be warned that:
|
||||
* Must be run as 'root', so either log on using the root account or use the `sudo` command, for example: `sudo ./disk_burnin.sh sda`
|
||||
|
||||
## Tests
|
||||
|
||||
Performs these steps:
|
||||
|
||||
1. Run SMART short test
|
||||
1. Run `badblocks`
|
||||
1. Run SMART extended test
|
||||
2. Run `badblocks`
|
||||
3. Run SMART extended test
|
||||
|
||||
The script calls `sleep` after starting each SMART test, using a duration based on the polling interval reported by the disk, after which it polls for test completion.
|
||||
|
||||
@@ -34,13 +38,15 @@ These indicate possible problems with the drive. You therefore may wish to abort
|
||||
The script extracts the drive model and serial number and creates a log filename of the form `burnin-[model]_[serial number].log`.
|
||||
|
||||
## `badblocks` Options
|
||||
|
||||
`badblocks` is invoked with the following options:
|
||||
- `-b 4096` : Use a block size of 4096
|
||||
- `-e 1` : Abort the test if an error is found (remove this option for full testing of drives)
|
||||
- `-v` : Verbose mode
|
||||
- `-o` : Write list of bad blocks found (if any) to a file named `burnin-[model]_[serial number].bb`
|
||||
- `-s` : Show progress
|
||||
- `-w` : Write-mode test, writes four patterns (0xaa, 0x55, 0x44, 0x00) on every disk block
|
||||
|
||||
* `-b 4096` : Use a block size of 4096
|
||||
* `-e 1` : Abort the test if an error is found (remove this option for full testing of drives)
|
||||
* `-v` : Verbose mode
|
||||
* `-o` : Write list of bad blocks found (if any) to a file named `burnin-[model]_[serial number].bb`
|
||||
* `-s` : Show progress
|
||||
* `-w` : Write-mode test, writes four patterns (0xaa, 0x55, 0x44, 0x00) on every disk block
|
||||
|
||||
The only required command-line argument is the device specifier, e.g.:
|
||||
|
||||
@@ -71,6 +77,7 @@ Also note that `badblocks` may issue the following warning under FreeBSD/FreeNAS
|
||||
## Operating System Compatibility
|
||||
|
||||
Tested under:
|
||||
|
||||
* FreeNAS 9.10.2-U1 (FreeBSD 10.3-STABLE)
|
||||
* FreeNAS 11.1-U7 (FreeBSD 11.1-STABLE)
|
||||
* FreeNAS 11.2-U8 (FreeBSD 11.2-STABLE)
|
||||
@@ -80,16 +87,19 @@ Tested under:
|
||||
## Drive Models Tested
|
||||
|
||||
The script should run successfully on any SATA disk with SMART capabilities, which includes just about all modern drives. It has been tested on these particular devices:
|
||||
|
||||
* HGST Deskstar NAS, UltraStar, UltraStar He10, and UltraStar He12 models
|
||||
* Western Digital Gold, Black, and Re models
|
||||
|
||||
## Prerequisites
|
||||
Requires the smartmontools, available at https://www.smartmontools.org
|
||||
|
||||
Uses: `grep`, `pcregrep`, `awk`, `sed`, `tr`, `sleep`, `badblocks`
|
||||
Requires the smartmontools, available at [www.smartmontools.org](https://www.smartmontools.org)
|
||||
|
||||
Tested with the static analysis tool at https://www.shellcheck.net to insure that the code is POSIX-compliant and free of issues.
|
||||
Uses: `grep`, `awk`, `sed`, `sleep`, `badblocks`
|
||||
|
||||
Tested with the static analysis tool at [www.shellcheck.net](https://www.shellcheck.net) to insure that the code is POSIX-compliant and free of issues.
|
||||
|
||||
## Author
|
||||
|
||||
Written by Keith Nash, March 2017.
|
||||
Modified on 19 August 2020.
|
||||
|
||||
509
disk-burnin.sh
Normal file → Executable file
509
disk-burnin.sh
Normal file → Executable file
@@ -68,7 +68,7 @@
|
||||
# your needs. In 'dry runs' the script does not actually perform any
|
||||
# SMART tests or invoke the sleep or badblocks programs. The script is
|
||||
# distributed with 'dry runs' enabled, so you will need to edit the
|
||||
# Dry_Run variable below, setting it to 0, in order to actually perform
|
||||
# DRY_RUN variable below, setting it to 0, in order to actually perform
|
||||
# tests on drives.
|
||||
#
|
||||
# Before using the script on FreeBSD systems (including FreeNAS) you must
|
||||
@@ -91,7 +91,7 @@
|
||||
#
|
||||
# Requires the smartmontools, available at https://www.smartmontools.org
|
||||
#
|
||||
# Uses: grep, pcregrep, awk, sed, tr, sleep, badblocks
|
||||
# Uses: grep, awk, sed, sleep, badblocks
|
||||
#
|
||||
# Written by Keith Nash, March 2017
|
||||
#
|
||||
@@ -121,7 +121,7 @@
|
||||
# surrounding the integer value in order to fetch it reliably.
|
||||
#
|
||||
# KN, 19 Aug 2020
|
||||
# Changed Dry_Run value so that dry runs are no longer the default setting.
|
||||
# Changed DRY_RUN value so that dry runs are no longer the default setting.
|
||||
# Changed badblocks call to exit immediately on first error.
|
||||
# Set logging directoryto current working directory using pwd command.
|
||||
# Reduced default tests so that we run:
|
||||
@@ -129,242 +129,331 @@
|
||||
# 2> badblocks
|
||||
# 3> Extended SMART test
|
||||
#
|
||||
########################################################################
|
||||
################################################################################
|
||||
|
||||
if [ $# -ne 1 ]; then
|
||||
echo "Error: not enough arguments!"
|
||||
echo "Usage is: $0 drive_device_specifier"
|
||||
################################################################################
|
||||
# PRE-EXECUTION VALIDATION
|
||||
################################################################################
|
||||
|
||||
# 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
|
||||
|
||||
Drive=$1
|
||||
|
||||
# Set Dry_Run to a non-zero value to test out the script without actually
|
||||
# running any tests; leave it set to zero to burn-in disks.
|
||||
|
||||
Dry_Run=0
|
||||
|
||||
# Directory specifiers for log and badblocks data files. Leave off the
|
||||
# trailing slash if you specify a value. Default is the current working
|
||||
# directory.
|
||||
|
||||
Log_Dir=$(pwd)
|
||||
BB_Dir=$(pwd)
|
||||
|
||||
# Alternative:
|
||||
#Log_Dir="."
|
||||
#BB_Dir="."
|
||||
|
||||
########################################################################
|
||||
#
|
||||
# Prologue
|
||||
#
|
||||
########################################################################
|
||||
|
||||
# Obtain the disk model and serial number:
|
||||
|
||||
Disk_Model=$(smartctl -i /dev/"$Drive" | grep "Device Model" | awk '{print $3, $4, $5}' | sed -e 's/^[ \t]*//;s/[ \t]*$//' | sed -e 's/ /_/')
|
||||
|
||||
if [ -z "$Disk_Model" ]; then
|
||||
Disk_Model=$(smartctl -i /dev/"$Drive" | grep "Model Family" | awk '{print $3, $4, $5}' | sed -e 's/^[ \t]*//;s/[ \t]*$//' | sed -e 's/ /_/')
|
||||
fi
|
||||
|
||||
Serial_Number=$(smartctl -i /dev/"$Drive" | grep -i "Serial Number" | awk '{print $3}' | sed -e 's/ /_/')
|
||||
|
||||
# Form the log and bad blocks data filenames:
|
||||
|
||||
Log_File="burnin-${Disk_Model}_${Serial_Number}.log"
|
||||
Log_File=$Log_Dir/$Log_File
|
||||
|
||||
BB_File="burnin-${Disk_Model}_${Serial_Number}.bb"
|
||||
BB_File=$BB_Dir/$BB_File
|
||||
|
||||
# Query the short and extended test duration, in minutes. Use the values to
|
||||
# calculate how long we should sleep after starting the SMART tests:
|
||||
|
||||
Short_Test_Minutes=$(smartctl -c /dev/"$Drive" | pcregrep -M "Short self-test routine.*\n.*recommended polling time:" | sed -e 's/)//;s/(//' | awk '{print $4}' | tr -d '\n')
|
||||
#printf "Short_Test_Minutes=[%s]\n" ${Short_Test_Minutes}
|
||||
|
||||
Extended_Test_Minutes=$(smartctl -c /dev/"$Drive" | pcregrep -M "Extended self-test routine.*\n.*recommended polling time:" | sed -e 's/)//;s/(//' | awk '{print $4}' | tr -d '\n')
|
||||
#printf "Extended_Test_Minutes=[%s]\n" ${Extended_Test_Minutes}
|
||||
|
||||
Short_Test_Sleep=$((Short_Test_Minutes*60))
|
||||
Extended_Test_Sleep=$((Extended_Test_Minutes*60))
|
||||
|
||||
# Selftest polling timeout interval, in hours
|
||||
Poll_Timeout_Hours=4
|
||||
|
||||
# Calculate the selftest polling timeout interval in seconds
|
||||
Poll_Timeout=$((Poll_Timeout_Hours*60*60))
|
||||
|
||||
# Polling sleep interval, in seconds:
|
||||
Poll_Interval=15
|
||||
|
||||
########################################################################
|
||||
#
|
||||
# Local functions
|
||||
#
|
||||
########################################################################
|
||||
|
||||
echo_str()
|
||||
{
|
||||
echo "$1" | tee -a "$Log_File"
|
||||
}
|
||||
|
||||
push_header()
|
||||
{
|
||||
echo_str "+-----------------------------------------------------------------------------"
|
||||
}
|
||||
|
||||
poll_selftest_complete()
|
||||
{
|
||||
l_rv=1
|
||||
l_status=0
|
||||
l_done=0
|
||||
l_pollduration=0
|
||||
|
||||
# Check SMART results for "The previous self-test routine completed"
|
||||
# Return 0 if the test has completed, 1 if we exceed our polling timeout interval
|
||||
|
||||
while [ $l_done -eq 0 ];
|
||||
do
|
||||
smartctl -a /dev/"$Drive" | grep -i "The previous self-test routine completed" > /dev/null 2<&1
|
||||
l_status=$?
|
||||
if [ $l_status -eq 0 ]; then
|
||||
echo_str "SMART self-test complete"
|
||||
l_rv=0
|
||||
l_done=1
|
||||
else
|
||||
# Check for failure
|
||||
smartctl -a /dev/"$Drive" | grep -i "of the test failed." > /dev/null 2<&1
|
||||
l_status=$?
|
||||
if [ $l_status -eq 0 ]; then
|
||||
echo_str "SMART self-test failed"
|
||||
l_rv=0
|
||||
l_done=1
|
||||
else
|
||||
if [ $l_pollduration -ge "${Poll_Timeout}" ]; then
|
||||
echo_str "Timeout polling for SMART self-test status"
|
||||
l_done=1
|
||||
else
|
||||
sleep ${Poll_Interval}
|
||||
l_pollduration=$((l_pollduration+Poll_Interval))
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
return $l_rv
|
||||
}
|
||||
|
||||
run_short_test()
|
||||
{
|
||||
push_header
|
||||
echo_str "+ Run SMART short test on drive /dev/${Drive}: $(date)"
|
||||
push_header
|
||||
if [ "${Dry_Run}" -eq 0 ]; then
|
||||
smartctl -t short /dev/"$Drive"
|
||||
echo_str "Short test started, sleeping ${Short_Test_Sleep} seconds until it finishes"
|
||||
sleep ${Short_Test_Sleep}
|
||||
poll_selftest_complete
|
||||
smartctl -l selftest /dev/"$Drive" | tee -a "$Log_File"
|
||||
else
|
||||
echo_str "Dry run: would start the SMART short test and sleep ${Short_Test_Sleep} seconds until the test finishes"
|
||||
# Check if running as root
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
echo "Please run as root" >&2
|
||||
exit 2
|
||||
fi
|
||||
echo_str "Finished SMART short test on drive /dev/${Drive}: $(date)"
|
||||
}
|
||||
|
||||
run_extended_test()
|
||||
{
|
||||
push_header
|
||||
echo_str "+ Run SMART extended test on drive /dev/${Drive}: $(date)"
|
||||
push_header
|
||||
if [ "${Dry_Run}" -eq 0 ]; then
|
||||
smartctl -t long /dev/"$Drive"
|
||||
echo_str "Extended test started, sleeping ${Extended_Test_Sleep} seconds until it finishes"
|
||||
sleep ${Extended_Test_Sleep}
|
||||
poll_selftest_complete
|
||||
smartctl -l selftest /dev/"$Drive" | tee -a "$Log_File"
|
||||
else
|
||||
echo_str "Dry run: would start the SMART extended test and sleep ${Extended_Test_Sleep} seconds until the test finishes"
|
||||
readonly USAGE=\
|
||||
"$(basename "$0") -- program to burn-in disks
|
||||
|
||||
Usage:
|
||||
$(basename "$0") [-h] [-f] [-o <directory>] <disk>
|
||||
|
||||
By default the program runs in dry mode and no data will be lost.
|
||||
|
||||
Options:
|
||||
-h show help text
|
||||
-f run in destructive, non-dry mode
|
||||
ALL DATA ON THE DISK WILL BE LOST!
|
||||
-o <directory> write log files to <directory>
|
||||
default: $(pwd)
|
||||
<disk> disk to burn-in: /dev/<disk>
|
||||
e.g. specify 'sda' to burn-in '/dev/sda'"
|
||||
|
||||
while getopts ':hfo:' option; do
|
||||
case "${option}" in
|
||||
h) echo "${USAGE}"
|
||||
exit
|
||||
;;
|
||||
f) DRY_RUN=0
|
||||
;;
|
||||
o) LOG_DIR="${OPTARG}"
|
||||
;;
|
||||
:) printf 'Missing argument for -%s\n' "${OPTARG}" >&2
|
||||
echo "${USAGE}" >&2
|
||||
exit 2
|
||||
;;
|
||||
\?) printf 'Illegal option: -%s\n' "${OPTARG}" >&2
|
||||
echo "${USAGE}" >&2
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
done
|
||||
shift $(( OPTIND - 1 ))
|
||||
|
||||
if [ -z "$1" ]; then
|
||||
echo "Missing option: <disk>" >&2
|
||||
echo "${USAGE}" >&2
|
||||
exit 2
|
||||
fi
|
||||
echo_str "Finished SMART extended test on drive /dev/${Drive}: $(date)"
|
||||
|
||||
################################################################################
|
||||
# CONSTANTS
|
||||
################################################################################
|
||||
|
||||
# Drive to burn-in
|
||||
readonly DRIVE="$1"
|
||||
|
||||
# Run in dry mode if -f wasn't provided
|
||||
[ -z "${DRY_RUN}" ] && DRY_RUN=1
|
||||
readonly DRY_RUN
|
||||
|
||||
# Set to working directory if -o <directory> wasn't provided
|
||||
[ -z "${LOG_DIR}" ] && LOG_DIR="$(pwd)"
|
||||
# Trim trailing slashes
|
||||
LOG_DIR="$(printf '%s' "${LOG_DIR}" | awk '{gsub(/\/+$/, ""); printf $1}')"
|
||||
readonly LOG_DIR
|
||||
|
||||
# System information
|
||||
readonly HOSTNAME="$(hostname)"
|
||||
readonly OS_FLAVOR="$(uname)"
|
||||
|
||||
# SMART static information
|
||||
readonly SMART_INFO="$(smartctl --info "/dev/${DRIVE}")"
|
||||
readonly SMART_CAPABILITIES="$(smartctl --capabilities "/dev/${DRIVE}")"
|
||||
|
||||
##################################################
|
||||
# Get SMART information value.
|
||||
# Globals:
|
||||
# SMART_INFO
|
||||
# Arguments:
|
||||
# value identifier:
|
||||
# !!! Only TWO WORD indentifiers are supported !!!
|
||||
# !!! Querying e.g. "ATA Version is" will fail !!!
|
||||
# - Device Model
|
||||
# - Model Family
|
||||
# - Serial Number
|
||||
# Outputs:
|
||||
# Write value to stdout.
|
||||
##################################################
|
||||
get_smart_info_value() {
|
||||
# $1=$2=""; select all but first two columns
|
||||
# gsub(/^[ \t]+|[ \t]+$/, ""); replace leading and trailing whitespace
|
||||
# gsub(/ /, "_"); replace remaining spaces with underscores
|
||||
# printf $1 print result without newline at the end
|
||||
printf '%s' "${SMART_INFO}" \
|
||||
| grep "$1" \
|
||||
| awk '{$1=$2=""; gsub(/^[ \t]+|[ \t]+$/, ""); gsub(/ /, "_"); printf $1}'
|
||||
}
|
||||
|
||||
##################################################
|
||||
# Get SMART recommended test duration, in minutes.
|
||||
# Globals:
|
||||
# SMART_CAPABILITIES
|
||||
# Arguments:
|
||||
# test type:
|
||||
# - Short
|
||||
# - Extended
|
||||
# - Conveyance
|
||||
# Outputs:
|
||||
# Write duration to stdout.
|
||||
##################################################
|
||||
get_smart_test_duration() {
|
||||
# '/'"$1"' self-test routine/ match duration depending on test type arg
|
||||
# getline; jump to next line
|
||||
# gsub(/\(|\)/, ""); remove parantheses
|
||||
# printf $4 print 4th column without newline at the end
|
||||
printf '%s' "${SMART_CAPABILITIES}" \
|
||||
| awk '/'"$1"' self-test routine/{getline; gsub(/\(|\)/, ""); printf $4}'
|
||||
}
|
||||
|
||||
# Get disk model
|
||||
DISK_MODEL="$(get_smart_info_value "Device Model")"
|
||||
[ -z "${DISK_MODEL}" ] && DISK_MODEL="$(get_smart_info_value "Model Family")"
|
||||
readonly DISK_MODEL
|
||||
|
||||
# Get disk serial number
|
||||
readonly SERIAL_NUMBER="$(get_smart_info_value "Serial Number")"
|
||||
|
||||
# The script initially sleeps for a duration after a test is started.
|
||||
# Afterwards the completion status is repeatedly polled.
|
||||
|
||||
# SMART short test duration
|
||||
readonly SHORT_TEST_MINUTES="$(get_smart_test_duration "Short")"
|
||||
readonly SHORT_TEST_SECONDS="$(( SHORT_TEST_MINUTES * 60))"
|
||||
|
||||
# SMART extended test duration
|
||||
readonly EXTENDED_TEST_MINUTES="$(get_smart_test_duration "Extended")"
|
||||
readonly EXTENDED_TEST_SECONDS="$(( EXTENDED_TEST_MINUTES * 60 ))"
|
||||
|
||||
# Maximum duration the completion status is polled
|
||||
readonly POLL_TIMEOUT_HOURS=4
|
||||
readonly POLL_TIMEOUT_SECONDS="$(( POLL_TIMEOUT_HOURS * 60 * 60))"
|
||||
|
||||
# Sleep interval between completion status polls
|
||||
readonly POLL_INTERVAL_SECONDS=15
|
||||
|
||||
# Form log file names
|
||||
readonly LOG_FILE="${LOG_DIR}/burnin-${DISK_MODEL}_${SERIAL_NUMBER}.log"
|
||||
readonly BB_File="${LOG_DIR}/burnin-${DISK_MODEL}_${SERIAL_NUMBER}.bb"
|
||||
|
||||
################################################################################
|
||||
# FUNCTIONS
|
||||
################################################################################
|
||||
|
||||
##################################################
|
||||
# Log informational message.
|
||||
# Globals:
|
||||
# LOG_FILE
|
||||
# Arguments:
|
||||
# Message to log.
|
||||
# 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 emphasized header message.
|
||||
# Arguments:
|
||||
# Message to log.
|
||||
##################################################
|
||||
log_header()
|
||||
{
|
||||
log_info "+-----------------------------------------------------------------------------"
|
||||
log_info "+ $1"
|
||||
log_info "+-----------------------------------------------------------------------------"
|
||||
}
|
||||
|
||||
##################################################
|
||||
# Poll repeatedly whether SMART self-test has completed.
|
||||
# Globals:
|
||||
# DRIVE
|
||||
# POLL_INTERVAL_SECONDS
|
||||
# POLL_TIMEOUT_SECONDS
|
||||
# Arguments:
|
||||
# None
|
||||
# Returns:
|
||||
# 0 if success or failure.
|
||||
# 1 if timeout threshold exceeded.
|
||||
##################################################
|
||||
poll_selftest_complete()
|
||||
{
|
||||
l_poll_duration_seconds=0
|
||||
while [ "${l_poll_duration_seconds}" -lt "${POLL_TIMEOUT_SECONDS}" ]; do
|
||||
smartctl --all "/dev/${DRIVE}" | grep -i "The previous self-test routine completed" > /dev/null 2<&1
|
||||
l_status="$?"
|
||||
if [ "${l_status}" -eq 0 ]; then
|
||||
log_info "SMART self-test succeeded"
|
||||
return 0
|
||||
fi
|
||||
smartctl --all "/dev/${DRIVE}" | grep -i "of the test failed." > /dev/null 2<&1
|
||||
l_status="$?"
|
||||
if [ "${l_status}" -eq 0 ]; then
|
||||
log_info "SMART self-test failed"
|
||||
return 0
|
||||
fi
|
||||
sleep "${POLL_INTERVAL_SECONDS}"
|
||||
l_poll_duration_seconds="$(( l_poll_duration_seconds + POLL_INTERVAL_SECONDS ))"
|
||||
done
|
||||
log_info "SMART self-test timeout threshold exceeded"
|
||||
return 1
|
||||
}
|
||||
|
||||
##################################################
|
||||
# Run SMART test and log results.
|
||||
# Globals:
|
||||
# DRIVE
|
||||
# LOG_FILE
|
||||
# Arguments:
|
||||
# Test type:
|
||||
# - short
|
||||
# - long
|
||||
# Test duration in seconds.
|
||||
##################################################
|
||||
run_smart_test()
|
||||
{
|
||||
log_header "Run SMART $1 test"
|
||||
if [ "${DRY_RUN}" -eq 0 ]; then
|
||||
smartctl --test="$1" "/dev/${DRIVE}"
|
||||
log_info "SMART $1 test started, awaiting completion for $2 seconds ..."
|
||||
sleep "$2"
|
||||
poll_selftest_complete
|
||||
smartctl --log=selftest "/dev/${DRIVE}" | tee -a "${LOG_FILE}"
|
||||
else
|
||||
log_info "Dry run: would start the SMART $1 test and sleep $2 seconds until the test finishes"
|
||||
fi
|
||||
log_info "Finished SMART short test"
|
||||
}
|
||||
|
||||
##################################################
|
||||
# Run badblocks test.
|
||||
# !!! ALL DATA ON THE DISK WILL BE LOST !!!
|
||||
# Globals:
|
||||
# BB_File
|
||||
# DRIVE
|
||||
# Arguments:
|
||||
# None
|
||||
##################################################
|
||||
run_badblocks_test()
|
||||
{
|
||||
push_header
|
||||
echo_str "+ Run badblocks test on drive /dev/${Drive}: $(date)"
|
||||
push_header
|
||||
if [ "${Dry_Run}" -eq 0 ]; then
|
||||
#
|
||||
# This is the command which erases all data on the disk:
|
||||
#
|
||||
badblocks -b 4096 -wsv -e 1 -o "$BB_File" /dev/"$Drive"
|
||||
log_header "Running badblocks test"
|
||||
if [ "${DRY_RUN}" -eq 0 ]; then
|
||||
badblocks -b 4096 -wsv -e 1 -o "${BB_File}" "/dev/${DRIVE}"
|
||||
else
|
||||
echo_str "Dry run: would run badblocks -b 4096 -wsv -e 1 -o ${BB_File} /dev/${Drive}"
|
||||
log_info "Dry run: would run badblocks -b 4096 -wsv -e 1 -o ${BB_File} /dev/${DRIVE}"
|
||||
fi
|
||||
echo_str "Finished badblocks test on drive /dev/${Drive}: $(date)"
|
||||
log_info "Finished badblocks test"
|
||||
}
|
||||
|
||||
########################################################################
|
||||
#
|
||||
# Action begins here
|
||||
#
|
||||
########################################################################
|
||||
################################################################################
|
||||
# ACTIONS BEGINS HERE
|
||||
################################################################################
|
||||
|
||||
if [ -e "$Log_File" ]; then
|
||||
rm "$Log_File"
|
||||
# Create log directory if it doesn't exist
|
||||
mkdir -p -- "${LOG_DIR}" || exit 2
|
||||
|
||||
if [ -e "${LOG_FILE}" ]; then
|
||||
rm "${LOG_FILE}"
|
||||
fi
|
||||
|
||||
push_header
|
||||
echo_str "+ Started burn-in of /dev/${Drive} : $(date)"
|
||||
push_header
|
||||
log_header "Started burn-in"
|
||||
|
||||
echo_str "Host: $(hostname)"
|
||||
echo_str "Drive Model: ${Disk_Model}"
|
||||
echo_str "Serial Number: ${Serial_Number}"
|
||||
echo_str "Short test duration: ${Short_Test_Minutes} minutes"
|
||||
echo_str "Short test sleep duration: ${Short_Test_Sleep} seconds"
|
||||
echo_str "Extended test duration: ${Extended_Test_Minutes} minutes"
|
||||
echo_str "Extended test sleep duration: ${Extended_Test_Sleep} seconds"
|
||||
echo_str "Log file: ${Log_File}"
|
||||
echo_str "Bad blocks file: ${BB_File}"
|
||||
log_info "Host: ${HOSTNAME}"
|
||||
log_info "OS Flavor: ${OS_FLAVOR}"
|
||||
log_info "Drive: /dev/${DRIVE}"
|
||||
log_info "Drive Model: ${DISK_MODEL}"
|
||||
log_info "Serial Number: ${SERIAL_NUMBER}"
|
||||
log_info "Short test duration: ${SHORT_TEST_MINUTES} minutes / ${SHORT_TEST_SECONDS} seconds"
|
||||
log_info "Extended test duration: ${EXTENDED_TEST_MINUTES} minutes / ${EXTENDED_TEST_SECONDS} seconds"
|
||||
log_info "Log file: ${LOG_FILE}"
|
||||
log_info "Bad blocks file: ${BB_File}"
|
||||
|
||||
# Run the test sequence:
|
||||
run_short_test
|
||||
#run_extended_test
|
||||
run_smart_test "short" "${SHORT_TEST_SECONDS}"
|
||||
run_badblocks_test
|
||||
#run_short_test
|
||||
run_extended_test
|
||||
run_smart_test "long" "${EXTENDED_TEST_SECONDS}"
|
||||
|
||||
# Emit full device information to log:
|
||||
push_header
|
||||
echo_str "+ SMART information for drive /dev/${Drive}: $(date)"
|
||||
push_header
|
||||
smartctl -x -v 7,hex48 /dev/"$Drive" | tee -a "$Log_File"
|
||||
log_header "SMART and non-SMART information"
|
||||
smartctl --xall --vendorattribute=7,hex48 "/dev/${DRIVE}" | tee -a "${LOG_FILE}"
|
||||
|
||||
push_header
|
||||
echo_str "+ Finished burn-in of /dev/${Drive} : $(date)"
|
||||
push_header
|
||||
log_header "Finished burn-in"
|
||||
|
||||
# Clean up the log file:
|
||||
|
||||
osflavor=$(uname)
|
||||
|
||||
if [ "${osflavor}" = "Linux" ]; then
|
||||
sed -i -e '/Copyright/d' "${Log_File}"
|
||||
sed -i -e '/=== START OF READ/d' "${Log_File}"
|
||||
sed -i -e '/SMART Attributes Data/d' "${Log_File}"
|
||||
sed -i -e '/Vendor Specific SMART/d' "${Log_File}"
|
||||
sed -i -e '/SMART Error Log Version/d' "${Log_File}"
|
||||
if [ "${OS_FLAVOR}" = "Linux" ]; then
|
||||
sed -i -e '/Copyright/d' "${LOG_FILE}"
|
||||
sed -i -e '/=== START OF READ/d' "${LOG_FILE}"
|
||||
sed -i -e '/SMART Attributes Data/d' "${LOG_FILE}"
|
||||
sed -i -e '/Vendor Specific SMART/d' "${LOG_FILE}"
|
||||
sed -i -e '/SMART Error Log Version/d' "${LOG_FILE}"
|
||||
fi
|
||||
|
||||
if [ "${osflavor}" = "FreeBSD" ]; then
|
||||
sed -i '' -e '/Copyright/d' "${Log_File}"
|
||||
sed -i '' -e '/=== START OF READ/d' "${Log_File}"
|
||||
sed -i '' -e '/SMART Attributes Data/d' "${Log_File}"
|
||||
sed -i '' -e '/Vendor Specific SMART/d' "${Log_File}"
|
||||
sed -i '' -e '/SMART Error Log Version/d' "${Log_File}"
|
||||
if [ "${OS_FLAVOR}" = "FreeBSD" ]; then
|
||||
sed -i '' -e '/Copyright/d' "${LOG_FILE}"
|
||||
sed -i '' -e '/=== START OF READ/d' "${LOG_FILE}"
|
||||
sed -i '' -e '/SMART Attributes Data/d' "${LOG_FILE}"
|
||||
sed -i '' -e '/Vendor Specific SMART/d' "${LOG_FILE}"
|
||||
sed -i '' -e '/SMART Error Log Version/d' "${LOG_FILE}"
|
||||
fi
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017 by Keith Nash
|
||||
Original work Copyright (c) 2017 by Keith Nash
|
||||
Modified work Copyright (c) 2020 by Michael Schnerring
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
Reference in New Issue
Block a user