Thursday, June 26, 2008

pyVerify version 2

Following on from my previous post that shows how to verify cd or dvd integrity, I have this following update:
  1. The volumeid.sh script now reads the whole isoinfo -d -i from the dvd and pipes it through to md5sum to generate a "signature" that identifies the disk. The thinking here is that it would be near impossible to have have two disk headers that match completely. Even those that share volume ids... For example openSUSE 11.0 i386 and openSUSE 11.0 x86_64
  2. The Verify class now includes checking for more than one row in the database that has the same volume label. ( md5sum result from volumeid.sh ) This is to catch anything that matches for some strange reason.
The updated code for all the files is included below.

volumeid.sh

#!/bin/sh
#
# small utility to find the md5sum of the isoinfo header information
#

isoinfo -d -i /dev/cdrom | md5sum | cut -d " " -f 1


verify.sh

#!/bin/sh
#

# Start with verifying CDs
#

device="/dev/cdrom"
checksumtype=$1

#Find details of the device
blocksize=`isoinfo -d -i $device | grep "^Logical block size is:" | cut -d " " -f 5`
if test "$blocksize" = ""; then
echo catdevice FATAL ERROR: Blank blocksize >&2
exit 1
fi

blockcount=`isoinfo -d -i $device | grep "^Volume size is:" | cut -d " " -f 4`
if test "$blockcount" = ""; then
echo catdevice FATAL ERROR: Blank blockcount >&2
exit 1
fi

command="dd if=$device bs=$blocksize count=$blockcount conv=notrunc,noerror status=noxfer"

# execute the command to read the disk and pipe through md5sum or sha1sum
result=`$command | $checksumtype`

#get the checksum
checksumresult=`echo $result | cut -d " " -f1`

echo $checksumresult


Verify.py

#!/usr/bin/env python

#===============================================================================
# Version information
# Version 0.1 Use Volume ID from isoinfo to identify current dvd/cd
# Version 0.2 Use an MD5SUM of the whole header found by isoinfo to
# identify the cd/dvd - This is called the signature in further
# comments
#===============================================================================

import MySQLdb
import popen2
import string

class Verify:

volumeid=''
checksumtype='md5sum'
goodchecksum=''

#===============================================================================
# Use volumeid.sh to find the signature of the disk
# and checks it against the database.
# If no match is found then report and exit. Otherwise
# checksum details are stored in class variables.
#===============================================================================

def __init__(self):

#===============================================================================
# get the signature from the inserted disk.
# Check for errors
# Store the signature in self.volumeid
#===============================================================================

(fout, fin, ferr) = popen2.popen3('./volumeid.sh')

errLineCount = 0
while True:
if ferr.readline():
errLineCount += 1
else:
break

if errLineCount > 0:
print "Errors were found."
exit()

id = ''
while True:
c = fout.read(1)
if c != "\n":
id += c
else:
break
self.volumeid = id

fout.close()
fin.close()

#===============================================================================
# Connect to database
# Find the distro with a distro_label matching the signature
#===============================================================================

conn = MySQLdb.connect(host = 'localhost',
user = 'root',
passwd = 'greycat',
db = 'cdburner' )
cursor = conn.cursor(MySQLdb.cursors.DictCursor)
sql = "SELECT * FROM distro WHERE distro_label = '%s'" % self.volumeid
cursor.execute(sql)

rows = cursor.fetchall()

#===============================================================================
# We still want to make sure there are no duplicates in the database.
# I would expect this to not ever happen as the block count is stored
# in the header and it would be quite unusual for two different CD or DVDs
# to have the same header details and block counts.
#===============================================================================

if( len(rows) > 1 ):
row = self.confirm(rows)
elif ( len(rows) < 1 ):
print "Could not find a matching record in the database."
print rows
print "SQL: %s" % sql
print "Quitting..."
exit()
else:
row = rows[0]

#===============================================================================
# Retrieve details of full checksum and checksum type
# from the database.
# Report findings and inform what's happening next.
#===============================================================================

if row["hash_type"] == 1:
self.checksumtype = 'md5sum'
else:
self.checksumtype = 'sha1sum'
self.goodchecksum = row['hash_detail']

print "Found [ %s ] in drive" % row['distro_name']
print "..."
print "performing %s check on disk now..." % self.checksumtype

cursor.close()
conn.close()

#===============================================================================
# Find the checksum of the inserted disk.
# using the external command verify.sh
#===============================================================================

cmd = "./verify.sh %s" % self.checksumtype
print "Executing ... %s " % cmd

(fout, fin) = popen2.popen2(cmd)
checksum = ''
while True:
c = fout.read(1)
if c != "\n":
checksum += c
else:
break
fout.close()
fin.close()

if checksum == self.goodchecksum:
print "Good Checksum : %s" % self.goodchecksum
print "Checksum found: %s" % checksum
print "DISK SUCCESSFULLY VERIFIED"
else:
print "Good Checksum : %s" % self.goodchecksum
print "Checksum found: %s" % checksum
print "*** ERROR *** DISK COULD NOT BE SUCCESSFULLY VERIFIED *** ERROR ***"

#===============================================================================
# We have more than one option. Ask for clarification
# Example. openSUSE 11 has the same volume id for both
# i386 and x86_64
# Keep asking until y or q entered.
#===============================================================================
def confirm(self,rows):
if len(rows) > 1:
while True:
print "Please select the ID that matches the media you wish to verify"
print "ID - Name"
count = 1
for row in rows:
print "%2d - %s" % (count, row["distro_name"])
count += 1
selected = raw_input(">")
print "You selected %s" % rows[int(selected)-1]["distro_name"]
confirmed = raw_input( "Is this ok? (y=yes, n=no, q=quit)" )
if ( string.lower(confirmed) == 'y'):
break
elif ( string.lower(confirmed) == 'q'):
print "QUIT APP"
exit()
return rows[int(selected)-1]


if __name__ == "__main__":

print "DISK Verifier -- Console Application."
print "by David Latham ( The Linux CD Store ) 2008"
print " "
v = Verify()
exit()

Post a Comment