scripts/smart.run.test.sh

192 lines
5.7 KiB
Bash
Executable File
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/sh
# .. vim: foldmarker=[[[,]]]:foldmethod=marker
# This script will try to run a smart test on all compatible devices.
# The test can be passed as first argument.
# Vars [[[
debug="0"
## Colors [[[
c_redb='\033[1;31m'
c_magentab='\033[1;35m'
c_reset='\033[0m'
## ]]]
temp_dir=$(mktemp -d -t smart.run.test-XXXXXX.tmp)
smart_device_list="${temp_dir}/smart.device.list"
# ]]]
# Functions
## Print help message [[[
print_help_message() {
cat << HELP
usage: $(basename "${0}") [TEST TYPE]
Try to run a SMART test on all compatible devices.
positional arguments:
TEST TYPE Test type to run on all devices. Can be:
short (default) - runs SMART Short Self Test (usually under ten minutes)
long - runs SMART Extended Self Test (tens of minutes to
several hours).
EXAMPLE:
- Run a short test
$(basename "${0}") short
HELP
}
## ]]]
## Check arguments [[[
## Ensure arguments have the expected value
check_arguments() {
if ! printf -- '%s' "${test_to_run}" | grep -q -E -- "(short|long)"; then
printf "${c_redb}%-6b${c_reset}\n" "ERROR: Can't manage '${test_to_run}' test type."
print_help_message
exit 3
fi
}
## ]]]
## Manage the arguments [[[
manage_arguments() {
_nb_arg="${#}"
_all_args="${*}"
[ "${debug}" -eq "0" ] && printf "${c_magentab}%-6b${c_reset}\n" "DEBUG: manage_arguments func ${_nb_arg} argument(s) to manage. List:\n ${_all_args}"
## If help is needed [[[
if printf -- '%s' "${_all_args}" | grep -q -E -- "-h|--help|help"; then
print_help_message
exit 0
fi
## ]]]
## Manage arguments [[[
case "${_nb_arg}" in
0 )
## Set test to run to default (short)
test_to_run="short"
;;
1 )
test_to_run="${1}"
;;
* )
## More than managed number of arguments
print_help_message
exit 2
;;
esac
## ]]]
## Verify the content of arguments
check_arguments
}
## ]]]
## Test if a disk really support SMART [[[
## Smartctl can give an health status even without a full support
## of SMART for some type (eg. scsi or megaraid).
## Exemple: SMART support is: Unavailable - device lacks SMART capability.
is_disk_path_support_smart() {
_disk_path="${1}"
_disk_type="${2}"
_smarctl_support_result="${temp_dir}/smart.support.$(basename "${_disk_path}")"
smart_support_msg=""
[ "${debug}" -eq "0" ] && printf "${c_magentab}%-6b${c_reset}\n" "DEBUG: is_disk_path_support_smart func check if SMART is supported on: ${_disk_path} with ${_disk_type} TYPE."
## Create file
true > "${_smarctl_support_result}"
## Grep only "support" lines from disk's informations
smartctl --device="${_disk_type}" --info -- "${_disk_path}" | grep -E "^SMART support is:" -- >> "${_smarctl_support_result}"
## If the file is not empty
if test -s "${_smarctl_support_result}"; then
## Parse all "support" lines
while IFS= read -r _line; do
### If a line doesn't contain enable or available
if ! printf -- '%s' "${_line}" | grep -q -E -- "(Enabled|Available)"
then
smart_support_msg="${_line}"
[ "${debug}" -eq "0" ] && printf "${c_magentab}%-6b${c_reset}\n" "DEBUG: is_disk_path_support_smart func SMART is not fully supported on: ${_disk_path} with ${_disk_type} TYPE. See smartctl informations:\n${smart_support_msg}"
fi
done < "${_smarctl_support_result}"
else
smart_support_msg="ERROR: Enable to open ${_disk_path} DEVICE with ${_disk_type} TYPE. Be sure to have sufficient permission for this device."
printf "${c_redb}%-6b${c_reset}\n" "ERROR: Enable to open ${_disk_path} DEVICE with ${_disk_type} TYPE. Be sure to have sufficient permission for this device."
fi
}
## ]]]
## Test the type of disk with smartctl [[[
## Cause the scanned one might not be the one to use
choose_correct_type() {
_disk_path="${1}"
_scanned_disk_type="${2}"
_default_disk_type="auto"
disk_type=""
for _test_disk_type in "${_default_disk_type}" "${_scanned_disk_type}"; do
is_disk_path_support_smart "${_disk_path}" "${_test_disk_type}"
## If no message, the type is correct
if [ -z "${smart_support_msg}" ]; then
disk_type="${_test_disk_type}"
[ "${debug}" -eq "0" ] && printf "${c_magentab}%-6b${c_reset}\n" "DEBUG: choose_correct_disk_type func SMART seems fully supported on: ${_disk_path} with ${_test_disk_type} TYPE."
return
fi
done
}
## ]]]
# Get the arguments's list and check values
manage_arguments "${@}"
# Create file
true > "${smart_device_list}"
# Get the list of all available devices
smartctl --scan >> "${smart_device_list}"
# If the devices list is not empty
if test -s "${smart_device_list}"; then
while IFS= read -r LINE; do
## Get device path
disk_path=$(echo "${LINE}" | cut -d" " -f1)
## Get scanned type
scanned_disk_type=$(echo "${LINE}" | cut -d" " -f3)
[ "${debug}" -eq "0" ] && printf "\n${c_magentab}%-6b${c_reset}\n" "DEBUG: smartctl scan ${disk_path} with TYPE ${scanned_disk_type}."
## Try to determine the best type
choose_correct_type "${disk_path}" "${scanned_disk_type}"
## If no correct type was found for this device
if [ -z "${disk_type}" ]; then
[ "${debug}" -eq "0" ] && printf "${c_magentab}%-6b${c_reset}\n" "DEBUG: SMART is not fully supported on ${disk_path}."
else
[ "${debug}" -eq "0" ] && printf "${c_magentab}%-6b${c_reset}\n" "DEBUG: Run a ${test_to_run} SMART test on disk ${disk_path}, with ${disk_type} TYPE."
smartctl --device="${disk_type}" --test="${test_to_run}" -- "${disk_path}"
fi
done < "${smart_device_list}"
# If the file is empty
else
printf "${c_redb}%-6b${c_reset}\n" "ERROR: The device list looks empty, check ${smart_device_list} file and \`smartctl --scan\` command."
exit 1
fi
# Remove temp_dir if debug is disable
[ "${debug}" -eq "0" ] || rm -rf -- "${temp_dir}"
exit 0