Sunday, February 5, 2017

Block device tester

I made this script to test block devices. First argument is the block device to test.
#! /usr/bin/ruby 
# Will quit in case some corrupt blocks are found and will print which position (from the offset) was a corrupt block found.
# First arg -- the block device.
require "securerandom"
require 'digest'
# Block size -- no. of Bytes to write at a time. Script will consume this much memory.
Bs = 9*1024*1024
Multiplyer = 6
# Returns random data of size bs. multiplyer specifies over how much interval to repeat the random data. The data drawn from the random no. generator will be bs/multiplyer
def getRandom(multiplyer, bs)
 randomDataUnit = (bs.to_f/multiplyer.to_f).ceil
 randomData = SecureRandom.random_bytes(randomDataUnit)
 randomData *= multiplyer
 if randomData.bytesize > bs
  randomData = randomData.byteslice(0, bs)
 end
 return randomData
end

# Open device
devwio = IO.new(IO.sysopen(ARGV[0], File::WRONLY|File::BINARY|File::SYNC))
devrio = IO.new(IO.sysopen(ARGV[0], File::RDONLY|File::BINARY|File::RSYNC))
devrio.sync = true
devwio.sync = true

# Calculate no. of blocks to write
devsize = `blockdev --getsize64 #{ARGV[0]}`.to_i
writeBlocks = (devsize.to_f/Bs.to_f).floor

# Write those blocks while testing
writeBlocks.times {
 data = getRandom(Multiplyer, Bs)
 devwio.write(data)
# TODO -- Move if to seperate function
 if (Digest::SHA1.digest data) != (Digest::SHA1.digest devrio.read(Bs))
  puts "\nData verification failed from #{devrio.pos-Bs} to #{devrio.pos}"
 else
  100.times {
   print "\x8"
  }
  print "Progress -- #{devrio.pos/1024/1024}MB"
 end
}
# Handel remaining blocks.
data = getRandom(1, devsize-(writeBlocks*Bs))
devwio.write(data)
# TODO -- Move if to seperate function
if (Digest::SHA1.digest data) != (Digest::SHA1.digest devrio.read)
  puts "\nData verification failed from #{devrio.pos-Bs} to #{devrio.pos}"
else
 100.times {
  print "\x8"
 }
 print "Last #{devrio.pos/1024/1024}MB"
end
puts
devwio.close
devrio.close