Dependencies:

#!/usr/bin/env ruby

require 'mmap'
require 'hexdump'
require 'raid5'

base = "stride"
base = sprintf("%s/%s", File.dirname(__FILE__), base)

badblocks = File.open('%s/bad' % base, 'w')

bstart = 147060
blocks = 171520
blksz = 512
zeroes = "\0" * blksz

sda = Mmap.new('%s/sda' % base, 'r')
sdb = Mmap.new('%s/sdb' % base, 'rw')
sdc = Mmap.new('%s/sdc-good' % base, 'r')
sdd = Mmap.new('%s/sdd' % base, 'r')
sde = Mmap.new('%s/sde' % base, 'r')

[ sda, sdb, sdc, sdd, sde ].each {|map| map.madvise(Mmap::MADV_DONTNEED) }

Range.new(bstart, blocks - 1).each {|index|
  if index % 8 == 0
    printf("\r %06u/%06u ", index, blocks - 1)
    STDOUT.flush
  end

  offset = blksz * index
  b_sda = sda[offset, blksz]
  b_sdb = sdb[offset, blksz]
  b_sdc = sdc[offset, blksz]
  b_sdd = sdd[offset, blksz]
  b_sde = sde[offset, blksz]

  unless xor_block(b_sda, b_sdb, b_sdc, b_sdd, b_sde) == zeroes
    printf("\r %06u/%06u %s ", index, blocks - 1, "Mismatch")

    resolution = "Untouched"
    if b_sdb == zeroes
      good_sdb = xor_block(b_sda, b_sdc, b_sdd, b_sde)
      sdb[offset, blksz] = good_sdb
      sdb.flush
      resolution = "Repaired"
    end
    printf("%s\n", resolution)

    # Log the details of the failure
    badblocks << sprintf("====\n#{index} - Z:%s\n", (b_sdb == zeroes).inspect)
    badblocks << "%s\n" % resolution
    badblocks << hexdump(b_sdb) unless b_sdb == zeroes
    badblocks << "Should be\n"
    badblocks << hexdump(xor_block(b_sda, b_sdc, b_sdd, b_sde))
    badblocks << "\n"
  end
}

printf("\r %1$06u/%1$06u\nAll done!\n", blocks - 1)

exit
kaboom unless xor_block(sda, sdb, sdc, sdd) == sde

#sdb = xor_block(sda, sdc, sdd, sde)
#File.open('%s/sdb' % base, 'w').write(sdb)

# dd if=sdb of=/dev/sdb bs=512 count=8 seek=976601648