diff --git a/smartdrivecheck.sh b/smartdrivecheck.sh new file mode 100644 index 0000000..3ab50e2 --- /dev/null +++ b/smartdrivecheck.sh @@ -0,0 +1,119 @@ +#!/usr/bin/env bash + +set -euo pipefail + +SMARTCTL="/usr/sbin/smartctl" +BADBLOCKS="/sbin/badblocks" + +usage() { + echo "Usage: $(basename "$0") " >&2 +} + +check_dependencies() { + for program in "$SMARTCTL" "$BADBLOCKS"; do + if ! command -v "$program" &>/dev/null; then + echo "Error: $program is not installed or not executable" >&2 + exit 1 + fi + done +} + +validate_device() { + local device="$1" + if [ ! -b "$device" ]; then + echo "Error: $device is not a valid block device" >&2 + usage + exit 1 + fi +} + +enable_smart() { + local device="$1" + echo "Enabling SMART on $device..." + $SMARTCTL -q silent -s on -S on "$device" || { + echo "SMART enable failed. Retrying..." >&2 + $SMARTCTL -s on -S on "$device" || true + } +} + +check_smart_status() { + local device="$1" + echo "Checking SMART status..." + $SMARTCTL -q silent -H "$device" || { echo "SMART Health Check Failed" >&2; exit 1; } + $SMARTCTL -q silent -l error "$device" || { echo "SMART Error Log Check Failed" >&2; exit 1; } + $SMARTCTL -q silent -l selftest "$device" || { echo "SMART Self-Test Log Check Failed" >&2; exit 1; } +} + +run_self_tests() { + local device="$1" + local test_type="$2" + local sleep_time="$3" + + echo "Running $test_type test (estimated time: $sleep_time minutes)..." + $SMARTCTL -q silent -t "$test_type" "$device" + sleep "${sleep_time}m" + check_smart_status "$device" +} + +perform_write_test() { + local device="$1" + echo "Performing non-destructive write test on $device..." + $BADBLOCKS -s -n "$device" || { echo "Non-destructive write test failed" >&2; exit 1; } + check_smart_status "$device" +} + +parse_polling_times() { + local device="$1" + local tmp_file + tmp_file=$(mktemp /tmp/drivetest.XXXXXXXXXX) + + $SMARTCTL -c "$device" | awk ' + /^(Short|Extended|Conveyance) self-test routine/ { + test_type = toupper($1) + getline + time = $0 ~ /\(\s*[0-9]+\)/ ? $2 : 0 + printf "%s_SLEEP=%d\n", test_type, time + } + ' >"$tmp_file" + source "$tmp_file" + rm -f "$tmp_file" +} + +main() { + if [ $# -ne 1 ]; then + usage + exit 1 + fi + + local device="$1" + validate_device "$device" + check_dependencies + + if [[ "$(basename "$device" | sed 's/^\(..\).*$/\1/')" == "sd" ]]; then + SMARTCTL="$SMARTCTL -d ata" + fi + + enable_smart "$device" + check_smart_status "$device" + parse_polling_times "$device" + + if [ -n "${CONVEYANCE_SLEEP:-}" ]; then + run_self_tests "$device" "conveyance" "$CONVEYANCE_SLEEP" + elif [ -n "${SHORT_SLEEP:-}" ]; then + run_self_tests "$device" "short" "$SHORT_SLEEP" + else + echo "Skipping conveyance/short tests..." + fi + + perform_write_test "$device" + + if [ -n "${EXTENDED_SLEEP:-}" ]; then + run_self_tests "$device" "long" "$EXTENDED_SLEEP" + else + echo "Skipping extended test..." + fi + + echo "All tests completed successfully." +} + +main "$@"