#!/usr/bin/perl

use warnings;
use strict;

my $drive = $ARGV[0] || die "usage: $0 /dev/sda\n";
my $delay = 15;
my $rewrite_sectors = 16;

my $test_started = 0;

sub write_sector {
	my $s = shift;
	system "hdparm --write-sector $s --yes-i-know-what-i-am-doing $drive";
}

sub smart_test {
	my $sector = shift;
	my $cmd = "smartctl -t select,$sector-max $drive";
	warn "$cmd\n";
	system $cmd;
	$test_started = 1;
}

sub smart {
	my $cmd = "smartctl -l selective $drive";
	warn "$cmd\n";
	open(my $fh, '-|', $cmd);
	while(<$fh>) {
		chomp;
		print "# $_\n";
		if ( m/Completed_read_failure.*\((\d+)-\d+\)/ ) {
			my $sector = $1;
			print "rewrite sector: $sector\n";
			foreach my $s ( $sector .. $sector + $rewrite_sectors ) {
				write_sector $s;
			}
			smart_test $sector;
			return 1;
		} elsif ( m/Self_test_in_progress/ ) {
			$test_started = 1;
			return 1;
		} elsif ( m/Not_testing/ ) {
			if ( $test_started ) {
				smart_last_error();
				return 1 if $test_started;
			}
			smart_test 0; # first-time invocation
		}
	}
	return 0;
}

sub smart_last_error {
	my $cmd = "smartctl -l selftest $drive";
	warn "$cmd\n";
	open(my $fh, '-|', $cmd);
	while(<$fh>) {
		chomp;
		print "# $_\n";
		if (/^#\s+1.+Completed: read failure\s+\S+\s+\S+\s+(\d+)/) {
			write_sector $1;
			smart_test $1;
			return 1;
		}
	}
}

smart_last_error || smart_test 0;

while ( smart ) {
	warn "sleep $delay s", ( $test_started ? " smart test running..." : "idle" ), "\n";
	sleep $delay;
}
