2019-06-12 09:22:28 -06:00
#!/usr/bin/perl -w
use strict ;
use warnings ;
use Digest::MD5 "md5_base64" ;
use POSIX ;
2019-06-24 11:22:30 -06:00
# create our random data and store it in ram so we can keep reusing it
2019-06-12 09:22:28 -06:00
open ( my $ drand , "<" , "/dev/urandom" ) ;
my $ clobber ;
read ( $ drand , $ clobber , 10240000 ) ;
close ( $ drand ) ;
my $ clobsum = md5_base64 ( $ clobber ) ;
2019-06-24 11:22:30 -06:00
# define some colors for conviniance
2019-06-12 09:22:28 -06:00
my % color = (
"red" = > "\e[0;31m" ,
"green" = > "\e[0;32m" ,
"reset" = > "\e[0m"
) ;
my @ failed = ( ) ;
2019-06-24 11:22:30 -06:00
my @ good = ( ) ;
2019-06-12 09:22:28 -06:00
my $ term = POSIX::Termios - > new ;
2019-06-24 11:22:30 -06:00
# for providing a waiting prompt
2019-06-12 09:22:28 -06:00
sub anykey {
print shift ;
my $ key ;
my $ oldflag = $ term - > getlflag ;
$ term - > setlflag ( ICANON ) ;
system "stty" , '-icanon' , 'eol' , "\001" ; #ISNT POSIX compliant
$ key = getc ( STDIN ) ;
$ term - > setlflag ( $ oldflag ) ;
system "stty" , 'icanon' , 'eol' , "^@" ;
return $ key
}
2019-06-24 11:22:30 -06:00
# to handle errors without using die
2019-06-12 09:22:28 -06:00
sub warning {
print shift ;
return 0 ;
}
2019-06-26 08:39:39 -06:00
# home made uniq function
2019-06-24 11:22:30 -06:00
sub uniq {
my % seen ;
return grep { ! $ seen { $ _ } + + } @ _ ;
}
# To get the list of devices we will be cleaning
2019-06-12 09:22:28 -06:00
sub getdisks {
2019-06-26 11:12:51 -06:00
my $ devices = `find /dev/sd*[a-z]` ;
2019-06-12 09:22:28 -06:00
my % listhash = ( ) ;
foreach ( split ( "\n" , $ devices ) ) {
my $ devicepath = $ _ ;
my $ serial = `udevadm info --query=all --name=$_ | grep SERIAL_SHORT | sed -e 's/^.*=//'` ;
2019-06-26 08:39:39 -06:00
my $ model = `udevadm info --query=all --name=$_ | grep ID_MODEL | sed -e 's/^.*=//'` ;
2019-06-12 09:22:28 -06:00
chomp ( $ serial ) ;
2019-06-26 08:39:39 -06:00
chomp ( $ model ) ;
2019-06-26 11:12:51 -06:00
if ( $ serial && $ model ) {
2019-06-12 09:22:28 -06:00
print $ devicepath . "\t" . $ serial . "\n" ;
$ listhash { $ _ } { "path" } = $ devicepath ;
$ listhash { $ _ } { "serial" } = $ serial ;
2019-06-26 08:39:39 -06:00
$ listhash { $ _ } { "model" } = $ model ;
2019-06-12 09:22:28 -06:00
} else { next ; }
}
return % listhash ;
}
2019-06-24 11:22:30 -06:00
# To while a drive
2019-06-12 09:22:28 -06:00
sub wipethemdrives {
my $ diskid = shift ;
my $ disks = shift ;
2019-06-26 08:39:39 -06:00
# Write
2019-06-12 09:22:28 -06:00
print $ disks - > { $ diskid } { "path" } . " - Serial:" . $ disks - > { $ diskid } { "serial" } . " is being wiped...\n" ;
2019-06-24 11:22:30 -06:00
open ( my $ diskw , ">" , $ disks - > { $ diskid } { "path" } ) or return warning ( "could not open " . $ disks - > { $ diskid } { "path" } ) ;
2019-06-12 09:22:28 -06:00
print $ diskw $ clobber ;
close ( $ diskw ) ;
system ( "sync" ) ;
print "Wipe attempt complete, checking...\n" ;
2019-06-26 08:39:39 -06:00
# Read
2019-06-24 11:22:30 -06:00
open ( my $ diskr , "<" , $ disks - > { $ diskid } { "path" } ) or return warning ( "could not open " . $ disks - > { $ diskid } { "path" } ) ;
2019-06-12 09:22:28 -06:00
my $ diskdata ;
read ( $ diskr , $ diskdata , 10240000 ) ;
my $ disksum = md5_base64 ( $ diskdata ) ;
close ( $ diskr ) ;
print "Disk Checksum: " . $ disksum . "\n" ;
if ( $ disksum eq $ clobsum ) {
print "Checksum " . $ color { "green" } . "PASSED!!!" . $ color { "reset" } . "\n" ;
print $ disks - > { $ diskid } { "path" } . " is clean.\n" ;
return 1 ;
} else {
print "Wipe Checksum: " . $ clobsum . "\n" ;
print "Checksum " . $ color { "red" } . "FAILED!!!" . $ color { "reset" } . "\n" ;
print $ disks - > { $ diskid } { "path" } . " did not take, it could be bad.\n" ;
return 0 ;
}
}
2019-06-24 11:22:30 -06:00
# to test a drive
2019-06-12 09:22:28 -06:00
sub smartcheck {
# Do our smart disk thing...
my $ diskid = shift ;
my $ disks = shift ;
print "Checking S.M.A.R.T. variables...\n" ;
print 'smartctl ' . $ disks - > { $ diskid } { "path" } . ' -A -f hex,id | grep "^0x"' . "\n" ;
( my $ smartcommand = `smartctl $disks->{$diskid}{"path"} -A -f hex,id | grep "^0x"` ) or ( print $! . "\ncould not check smart data, skipping\n" and return 1 ) ;
for ( split ( "\n" , $ smartcommand ) ) {
my @ smartdata = split ( /\s+/ , $ _ ) ;
$ disks - > { $ diskid } { "smart" } { $ smartdata [ 0 ] } { "id" } = $ smartdata [ 0 ] ;
$ disks - > { $ diskid } { "smart" } { $ smartdata [ 0 ] } { "name" } = $ smartdata [ 1 ] ;
$ disks - > { $ diskid } { "smart" } { $ smartdata [ 0 ] } { "flag" } = $ smartdata [ 2 ] ;
$ disks - > { $ diskid } { "smart" } { $ smartdata [ 0 ] } { "value" } = $ smartdata [ 3 ] ;
$ disks - > { $ diskid } { "smart" } { $ smartdata [ 0 ] } { "worst" } = $ smartdata [ 4 ] ;
$ disks - > { $ diskid } { "smart" } { $ smartdata [ 0 ] } { "thresh" } = $ smartdata [ 5 ] ;
$ disks - > { $ diskid } { "smart" } { $ smartdata [ 0 ] } { "type" } = $ smartdata [ 6 ] ;
$ disks - > { $ diskid } { "smart" } { $ smartdata [ 0 ] } { "updated" } = $ smartdata [ 7 ] ;
$ disks - > { $ diskid } { "smart" } { $ smartdata [ 0 ] } { "when_failed" } = $ smartdata [ 8 ] ;
$ disks - > { $ diskid } { "smart" } { $ smartdata [ 0 ] } { "raw_value" } = $ smartdata [ 9 ] ;
}
close ( $ smartcommand ) ;
2019-06-26 11:12:51 -06:00
for my $ smartentry ( sort { $ a cmp $ b } keys % { $ disks - > { $ diskid } { "smart" } } ) {
2019-06-12 09:22:28 -06:00
if ( $ disks - > { $ diskid } { "smart" } { $ smartentry } { "id" } =~ /0x05|0x07|0xc4|0xc5|0xc6|0xc7/ ) {
print $ disks - > { $ diskid } { "smart" } { $ smartentry } { "id" } . " " . $ disks - > { $ diskid } { "smart" } { $ smartentry } { "name" } . "\t" . $ disks - > { $ diskid } { "smart" } { $ smartentry } { "raw_value" } . "\t" ;
if ( $ disks - > { $ diskid } { "smart" } { $ smartentry } { "raw_value" } =~ /0|0\/0/ ) {
print $ color { "green" } . "Passed" . $ color { "reset" } . "\n" ;
2019-06-26 08:39:39 -06:00
} else { print $ color { "red" } . "Failed" . $ color { "reset" } . "\n" ; return 0 }
2019-06-12 09:22:28 -06:00
}
}
return 1 ;
}
2019-06-24 11:22:30 -06:00
# main loop
2019-06-12 09:22:28 -06:00
while ( ) {
my % disks = getdisks ( ) ;
my $ batchcount = keys % disks ;
print "About to wipe " . $ batchcount . " drives with the following serial numbers:\n" ;
2019-06-26 11:12:51 -06:00
foreach my $ diskid ( sort { $ a cmp $ b } keys % disks ) {
2019-06-12 09:22:28 -06:00
print $ disks { $ diskid } { "serial" } . "\n" ;
}
anykey ( "Hit any key to continue...\n" ) ;
2019-06-26 11:12:51 -06:00
foreach my $ diskid ( sort { $ a cmp $ b } keys % disks ) {
print "\e[0;0H\e[2J" ; # move cursor to 0,0 and then clear all text below.
2019-06-12 09:22:28 -06:00
print "=" x33 ;
printf '[ %-10s ]' , $ diskid ;
print "=" x33 ;
print "\n" ;
$ disks { $ diskid } { "wipe" } = wipethemdrives ( $ diskid , \ % disks ) ;
if ( $ disks { $ diskid } { "wipe" } == 1 ) {
$ disks { $ diskid } { "smartpass" } = smartcheck ( $ diskid , \ % disks ) ;
if ( $ disks { $ diskid } { "smartpass" } == 1 ) {
print "Smart looks good.\n" ;
2019-06-26 08:39:39 -06:00
push ( @ good , $ disks { $ diskid } { "serial" } . "\t" . $ disks { $ diskid } { "model" } ) ;
2019-06-12 09:22:28 -06:00
} else { push ( @ failed , $ disks { $ diskid } { "serial" } ) ; }
} else { push ( @ failed , $ disks { $ diskid } { "serial" } ) ; }
print "=" x80 ;
print "\n" x5 ;
}
2019-06-24 11:22:30 -06:00
print "These drives were successfully wiped and passed SMART, they may be put back into production:\n" ;
2019-06-26 08:39:39 -06:00
print $ color { "green" } . join ( "\n" , sort { $ a cmp $ b } uniq ( @ good ) ) . $ color { "reset" } ;
anykey ( "\nHit any key to see the list of failed drives. Please also note any drives that do not appear\non ether list. Those should be tried again (if they do not show up after three times assume falure)." ) ;
2019-06-24 11:22:30 -06:00
print "The folowing drives are bad, RMA or shred:\n" ;
print join ( "\n" , sort { $ a cmp $ b } uniq ( @ failed ) ) ;
2019-06-12 09:22:28 -06:00
@ failed = ( ) ;
2019-06-24 11:22:30 -06:00
@ good = ( ) ;
2019-06-26 08:39:39 -06:00
print $ color { "green" } . "-" x34 . $ color { "red" } . "\nWipe complete, insert more drives.\n" . $ color { "green" } . "-" x34 . "\n" ;
2019-06-12 09:22:28 -06:00
anykey ( "Hit any key when ready to continue...\n" ) ;
}