Python + Bash + isoinfo + mysql = Python CD Integrity Verifier
I have a requirement to verify by md5sum or sha1sum, CDs or DVDs that I burn - so I wrote a bunch of scripts. I am not saying that this is the best way to skin this particular cat, but it is working.
First of all a bit of background info.
This stuff only works on Linux because the commands make use of Linux tools such as isoinfo and dd. I am sure Windows command line equivalents exist...
I have a mysql database with one table in it that has the following fields:
Here is an example record:
In case you are wondering how I know the volume id - try this while you have a CD or DVD in your cd / dvd drive:
Requirements
This python script has one dependency. Basically I need my python script to be able to query the database.
Retrieving the volume id from the disk.
I have a small utility bash script that does this.
It does the following:
Reading the disk
In order to accurately read the CD we need to know some details about the cd first. There is a very useful script ( from which I borrowed all the technical stuff about finding the blocksizes and blockcounts required by dd ) I found the rawread.sh script here.
Here it is for your convenience:
Here is my modified version to suit a call from my python script.
This script does the same things as rawread.sh but lets the user specify a checksum type as a command line argument. When called from within our python script this bash script will simply return the real checksum of the disk in the cd / dvd device.
The python script.
I have tried to comment it so it all makes sense. I look forward to a lively discussion in the comments. I will soon know how many of my readers actaually care about python or, more to the point, how many readers I have...
All in all these scripts join together to provide a non technical user ( ie: My lovely wife ) the ability to verify Linux distros before she ships them out. Want to know more? Check out: http://www.thelinuxcdstore.com.
First of all a bit of background info.
This stuff only works on Linux because the commands make use of Linux tools such as isoinfo and dd. I am sure Windows command line equivalents exist...
I have a mysql database with one table in it that has the following fields:
distro_label --- Volume ID of CD or DVD distro_name ---- Name of the CD or DVD hash_type ------ 1 = md5sum, 2 = sha1sum hash_detail ---- Known good md5sum or sha1sum of the particular CD or DVD
Here is an example record:
distro_label --- Slack11d1 distro_name ---- Slackware 11 Disk 1 hash_type ------ 1 hash_detail ---- a7cfcb4be158beca63af21b3b4dbc69c
In case you are wondering how I know the volume id - try this while you have a CD or DVD in your cd / dvd drive:
[~]$ isoinfo -d -i /dev/cdrom
Requirements
This python script has one dependency. Basically I need my python script to be able to query the database.
- MySQL-python - Download and install from here or if you are in Fedora try: yum install MySQL-python
Retrieving the volume id from the disk.
I have a small utility bash script that does this.
#!/bin/sh # # small utility to find the volume id of a cd / dvd # isoinfo -d -i /dev/cdrom \ | grep "Volume id:" \ | cut -d ":" -f 2 \ | sed "s/ //g"
It does the following:
- read the iso info from the disk
- Find the line with the Volume id
- Cut out the second field delimited by ":"
- remove all spaces
Reading the disk
In order to accurately read the CD we need to know some details about the cd first. There is a very useful script ( from which I borrowed all the technical stuff about finding the blocksizes and blockcounts required by dd ) I found the rawread.sh script here.
Here it is for your convenience:
#!/bin/sh device=$1 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 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 fi command="dd if=$device bs=$blocksize count=$blockcount conv=notrunc,noerror" echo "$command" >&2 $command
Here is my modified version to suit a call from my python script.
#!/bin/sh # 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" # 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
This script does the same things as rawread.sh but lets the user specify a checksum type as a command line argument. When called from within our python script this bash script will simply return the real checksum of the disk in the cd / dvd device.
- Store the checksum type in a variable.
- Find the block size and block count values for the disk.
- Format the dd command
- Execute the dd command and pipe into checksum type. eg: dd .... | md5sum
- cut the resulting checksum from the output of the above.
- echo just the checksum
The python script.
I have tried to comment it so it all makes sense. I look forward to a lively discussion in the comments. I will soon know how many of my readers actaually care about python or, more to the point, how many readers I have...
#!/usr/bin/env python
#================================================================================
# MySQLdb is the only dependency required for this script.
# popen2 comes with standards python 2.5
#================================================================================
import MySQLdb
import popen2
class Verify:
volumeid=''
checksumtype='md5sum'
goodchecksum=''
#================================================================================
# Constructor uses volumeid.sh to find the volumeid if the cdrom
# and checks it against the database.
# If no match is found then an error is generated otherwise
# checksum details are stored in class variables.
#================================================================================
def __init__(self):
## Get the volumeid
# fout = stdout
# fin = stdin
# ferr = stderr
(fout, fin, ferr) = popen2.popen3('./volumeid.sh')
id = ''
## Check for errors
errLineCount = 0
while True:
if ferr.readline():
errLineCount += 1
else:
break
if errLineCount > 0:
print "Errors were found."
exit()
## We are reading each character of the standard out because
## we do not wish to capture the newline at the end.
while True:
c = fout.read(1)
if c != "\n":
id += c
else:
break
## Store the volumeid in the class variable.
self.volumeid = id
## Clean up.
fout.close()
fin.close()
## Establish mysql connection and query database.
conn = MySQLdb.connect(host = 'localhost',
user = 'resu',
passwd = 'drowsapp',
db = 'cdburner' )
cursor = conn.cursor(MySQLdb.cursors.DictCursor)
sql = "SELECT * FROM distro WHERE distro_label = '%s'" % self.volumeid
cursor.execute(sql)
row = cursor.fetchone()
## TO DO: Check for non existent entry in database and throw error.
## Find the required checksum type from the database.
if row["hash_type"] == 1:
self.checksumtype = 'md5sum'
else:
self.checksumtype = 'sha1sum'
## Find the known checksum from the database
self.goodchecksum = row['hash_detail']
## Print some information to the user.
print "Found [ %s ] in cd drive" % row['distro_name']
print "Good Checksum = %s" % self.goodchecksum
print "..."
print "performing %s check on disk now..." % self.checksumtype
## Clean up.
cursor.close()
conn.close()
## Read checksum from disk
## TO DO: change this to check for errors like the popen3 command above.
cmd = "./verify.sh %s" % self.checksumtype
(fout, fin) = popen2.popen2(cmd)
checksum = ''
## Same as above in terms of not wanting the newline at the end of stdout.
while True:
c = fout.read(1)
if c != "\n":
checksum += c
else:
break
## Clean up
fout.close()
fin.close()
## Compare the checksums and report!
if checksum == self.goodchecksum:
print "Checksum found: %s" % checksum
print "DISK SUCCESSFULLY VERIFIED"
else:
print "*** ERROR *** DISK COULD NOT BE SUCCESSFULLY VERIFIED *** ERROR ***"
## If this script is being executed then do this stuff.
## This block allows us to use the above as a class or library or as a simple script.
if __name__ == "__main__":
print "DISK Verifier -- Console Application."
print "by David Latham ( The Linux CD Store ) 2008"
v = Verify()
exit()
All in all these scripts join together to provide a non technical user ( ie: My lovely wife ) the ability to verify Linux distros before she ships them out. Want to know more? Check out: http://www.thelinuxcdstore.com.
Comments