seti $printhelp = $printhelp seti $help = $help if $help = 1 echo 'This will read the drive and write the data to an image file.' echo 'It uses PIO read commands and adjusts if extended commands are supported.' echo 'Please note that this program is in no way optimized for this,' echo ' and is very limited in features. echo 'This is not meant as a robust way to image a device.' echo 'Making an image using a script file will never be as fast as possible.' echo 'Reads are done in blocks (clusters) of 256 sectors.' echo 'This means that all warnings and errors show the position' echo ' of the first sector of the block, NOT the actual problem sector.' echo 'This requires the number variable startsector to be set.' echo 'This requires the number variable endsector to be set.' echo 'If endsector is set to 0, it will default to the last addressable sector.' echo 'This uses the identify device command to determine the last sector.' echo 'This requires the number variable timeout to be set.' echo 'Timeout is the time in milliseconds to wait before giving up on a command.' echo 'If timeout is set to 0, it will default to 10000ms.' echo 'This requires the string variable logfile to be set.' echo 'Logfile will capture all the warnings and errors.' echo 'If logfile is blank then no log will be produced.' echo 'This requires the string variable imagefile to be set.' echo 'Imagefile is the file where the data will be written.' echo 'If imagefile is blank then no image file will be produced.' echo 'Example:' echo 'hddsupertool -t /dev/sda -f ata_image_device timeout=0 startsector=0 endsector=0 logfile=="image.log" imagefile=="image.bin"' if $printhelp = 1 exit 0 endif echo 'Hit ENTER to continue...' userinput $choicestring previousscript endif echo 'This script is meant for testing, not actually imaging a drive.' echo 'While it may be somewhat capable, it has many limitations.' include good_subroutines sets $null = "" seti $using_menu = $using_menu seti $ask = 0 while 1 = 1 variablecheck $startsector if $error_level < 16 seti $ask = 1 elseif $using_menu = 1 seti $ask = 1 endif if $ask = 1 echo "Enter start sector, or leave blank for first:" userinput $choicestring if $choicestring != $null seti $startsector = $choicestring 0 break else seti $startsector = 0 break endif else break endif done seti $ask = 0 while 1 = 1 variablecheck $endsector if $error_level < 16 seti $ask = 1 elseif $using_menu = 1 seti $ask = 1 endif if $ask = 1 echo "Enter end sector, or leave blank for last:" userinput $choicestring if $choicestring != $null seti $endsector = $choicestring 0 break else seti $endsector = 0 break endif else break endif done seti $ask = 0 while 1 = 1 variablecheck $timeout if $error_level < 16 seti $ask = 1 elseif $using_menu = 1 seti $ask = 1 endif if $ask = 1 echo "Enter timeout in ms, or leave blank for default(10000ms):" userinput $choicestring if $choicestring != $null seti $timeout = $choicestring 0 break else seti $timeout = 10000 break endif else break endif done if $timeout = 0 seti $timeout = 10000 endif seti $timeout = $timeout * 1000 softtimeout $timeout seti $ask = 0 variablecheck $logfile if $error_level < 16 seti $ask = 1 elseif $using_menu = 1 seti $ask = 1 endif if $ask = 1 echo "Enter logfile name, or leave blank for no log:" userinput $choicestring sets $logfile = $choicestring endif seti $ask = 0 variablecheck $imagefile if $error_level < 16 seti $ask = 1 elseif $using_menu = 1 seti $ask = 1 endif if $ask = 1 echo "Enter image file name, or leave blank to not create an image:" userinput $choicestring sets $imagefile = $choicestring endif # get the size of the drive using identify device command buffersize 512 setreadpio ata28cmd 0 0 0 0 0 0xa0 0xec # check if command failed seti $command_failed = 0 gosub check_command_status if $command_failed = 1 echo "Identify device command failed!" gosub show_sense_data gosub show_ata_return_status previousscript endif # check if drive supports extended commands seti $tempnum = buffer 167 seti $extended = $tempnum & 4 # total addressable sectors if $extended > 0 seti $addressable = buffer 200 qw else seti $addressable = buffer 120 dw endif if $endsector = 0 seti $endsector = $addressable endif seti $blocksize = 256 seti $buffersize = $blocksize * 512 buffersize $buffersize setreadpio seti $currentposition = $startsector seti $previousposition = $currentposition seti $blockposition = $currentposition seti $processedsectors = 0 seti $totalsectors = $endsector - $startsector seti $errorcount = 0 if $logfile != $null #deletefile $logfile gettime sets $line = "# error log " $date writelog $logfile $line sets $line = "# cluster size is " $blocksize writelog $logfile $line endif gettime seti $displaytime = $time seti $redodisplay = 1 echo " " echo " " echo " " echo " " echo " " echo " " echo " " gettime seti $programstart = $time while $currentposition < $endsector seti $sector = $currentposition if $extended > 0 seti $features = 0 seti $count = $blocksize seti $LBAlow = $sector & 0xffff seti $temp = $sector > 16 seti $LBAmid = $temp & 0xffff seti $temp = $sector > 32 seti $LBAhigh = $temp & 0xffff seti $device = 0xe0 seti $command = 0x24 gettime seti $startreadtime = $time ata48cmd $features $count $LBAhigh $LBAmid $LBAlow $device $command gettime seti $endreadtime = $time else seti $features = 0 seti $count = $blocksize & 0xff seti $LBAlow = $sector & 0xff seti $temp = $sector > 8 seti $LBAmid = $temp & 0xff seti $temp = $sector > 16 seti $LBAhigh = $temp & 0xff seti $temp = $sector > 24 seti $LBAdevice = $temp & 0x0f seti $device = 0xe0 seti $device = $device | $LBAdevice seti $command = 0x20 gettime seti $startreadtime = $time ata28cmd $features $count $LBAlow $LBAmid $LBAhigh $device $command gettime seti $endreadtime = $time endif # check if command failed seti $command_failed = 0 gosub check_command_status if $command_failed = 1 seti $devicefault = $ata_return_status & 0x20 endif # write the data to the file if $imagefile != $null if $command_failed = 0 seti $writeoffset = $currentposition * 512 seti $writesize = $blocksize * 512 writebuffer $imagefile 0 $writeoffset $writesize endif endif seti $readtime = $endreadtime - $startreadtime if $command_failed = 1 seti $errorcount = $errorcount + 1 endif seti $showerror = 0 if $command_failed = 1 seti $showerror = 1 endif if $showerror > 0 upline upline upline upline upline upline upline seti $adjustedtime = $readtime / 1000 hex sets $errorstring = "e=0x" $ata_return_error " s=0x" $ata_return_status decimal if $direct_mode = 1 seti $command_status = $command_status & 0xf0 if $command_status = 0x20 sets $status = "BUSY" elseif $command_status = 0x30 sets $status = "TIMEOUT/RESET" elseif $command_status = 0x40 sets $status = "TIMEOUT/RESET/BUSY" elseif $command_status = 0x50 sets $status = "TIMEOUT" elseif $command_status = 0x60 sets $status = "NO DRQ" elseif $command_status = 0x70 sets $status = "WRONG DEVICE" else sets $status = "" endif else sets $status = "" endif sets $outputline = "ERROR " $status " " $currentposition " " $adjustedtime "ms " $errorstring echo $outputline echo $null echo $null echo $null echo $null echo $null echo $null echo $null seti $redodisplay = 1 if $logfile != $null writelog $logfile $outputline endif endif seti $elapsedtime = $endreadtime - $displaytime if $elapsedtime > 1000000 seti $redodisplay = 1 endif if $redodisplay = 1 seti $sectorstransferred = $currentposition - $previousposition seti $previousposition = $currentposition seti $bytestransferred = $sectorstransferred * 512 seti $adjustedbytes = $bytestransferred * 1000000 seti $currentspeed = $adjustedbytes / $elapsedtime seti $currentspeed = $currentspeed / 1000 gosub displayoutput seti $displaytime = $endreadtime endif seti $redodisplay = 0 if $devicefault > 0 echo "Device fault detected!" echo "Current position= " $currentposition gosub show_ata_return_status break endif seti $currentposition = $currentposition + $blocksize seti $processedsectors = $processedsectors + $blocksize # check if last read is less than blocksize seti $partial = $currentposition + $blocksize if $partial > $endsector if $currentposition < $endsector seti $blocksize = $endsector - $currentposition seti $buffersize = $blocksize * 512 buffersize $buffersize endif endif done if $devicefault = 0 gosub displayoutput endif previousscript end subroutine displayoutput upline upline upline upline upline upline echo " " gettime seti $totaltime = $time - $programstart seti $totalseconds = $totaltime / 1000000 seti $remainder = $totaltime % 1000000 seti $totalminutes = $totalseconds / 60 seti $seconds = $totalseconds % 60 seti $hours = $totalminutes / 60 seti $minutes = $totalminutes % 60 echo "elapsed time h:m:s = " $hours ":" $minutes ":" $seconds "." $remainder seti $positionpercent = $processedsectors * 100 seti $percentcomplete = $positionpercent / $totalsectors seti $remainder = $positionpercent % $totalsectors seti $remainder = $remainder * 100 seti $percentremainder = $remainder / $totalsectors if $percentremainder < 10 echo $percentcomplete ".0" $percentremainder "% complete " else echo $percentcomplete "." $percentremainder "% complete " endif echo "position= " $currentposition " " echo "speed= " $currentspeed " kB/s " echo "errors=" $errorcount " " endsubroutine