THE SPEECH BEFORE THE SCRIPT
tl;dr note you can just skip to the script below if you want
This script uses ddrescue (the newer one between gddrescue and ddrescue, so it uses gddrescue – note gddrescues command is actually ‘ddrescue’ and ddrescues command is actually ‘dd_rescue’, so below we are using ‘ddrescue’ which means we are using gddrescue… thus the newer one). You will need gddrescue, a simple apt-get update; “apt-get install gddrescue” will get it.
I use two commands to clone the a drive, as recommended in their man page. First I clone the good sections (its a quick run thru). Then all of the bad areas get reported to a log file (the good areas get reported as well), then the second run thru tells it to retry once per trouble area.
For example if we have a bad drive /dev/sdb and we are copying to /dev/sdg which is the good drive. Imagine /dev/sdb has 50 realloacted sectors and like 2 ata errors (thus its about to die soon).
NOTE – HOW TO TELL IF A DRIVE IS BAD: I get my SMART/health data about the drive with smartctl “smartctl -a /dev/sdb” Im used to the thumb rule that if you have over 50 reallocated sectors OR 1 or more ATA errors then its time for a drive replacement. ALSO if you have a count of both current pending sectors and offline uncorrectable that keeps growing (or doesnt go away) then its time for a clone.
Before starting the clone I need to make sure that /dev/sdb and /dev/sdg are not mounted (so that they just dont get in the way during the clone – this is for logical reasons). Also for logical reasons you need to save the log somewhere safe (obviously it cant be on /dev/sdb and it cant be on /dev/sdg per the previous requirement). Note the log files dont get that big, they are never over a megabyte. If you want… You can tail the log file during a clone to see what I mean (That they dont get that big, you will see why), log files of gddrescue are just bitmaps of what range of sectors are good and bad as the recovery goes on.
ddrescue -n /dev/sdb /dev/sdg /root/b2g.log
ddrescue -r1 /dev/sdb /dev/sdg /root/b2g.log
If this command cries about the file being not regular, then add the -f argument for force.
ddrescue -fn /dev/sdb /dev/sdg /root/b2g.log
ddrescue -fr1 /dev/sdb /dev/sdg /root/b2g.log
NOTE: you can increase -r1 to 2 or 3 or whatever number you wish if you wish to retry more then once on a bad sector (realize that with -r1 the system would have already tried 3 times if it fails, once with -n, and once with -r1 before the retry event, and three times after the first and only retry event – so with -r2 you will actaully be trying the bad sector 4 times, and with -r3 you will be trying it 5 times)
THE SCRIPT
The script speaks for it self in the comments
#!/bin/bash # # TOP LINE: note if you have sh & not bash, just change /bin/bash above to /bin/sh # # WHAT IS THIS: clone script with gddrescue for drives # REQUIREMENTS: make sure source and destination are unmounted (just to be on safe side so that nothing is used) # # HOW TO USE: ./ddkclone.sh <src> <dst> <log> # EXAMPLE: ./ddkclone.sh /dev/sdb /dev/sdg /root/b2g.log # # must have log argument (make sure log saves to a different location then source or destination) # for logical reasons, you dont want the log saving to where your cloning to or from # # WHAT THIS DOES: # first it copies good areas, when thats done it starts copying whats left over (which is bad sections) # it knows whats left over and only retries those areas # because the log stores information about where its successfully recovered data from and where it had trouble # it retrys once on bad sections that give it trouble #ue, without the g - to get it "apt-get install gddrescue") # Best way to run is with nohup (or in a screen or dtach session) - that way if putty or terminal closes it still runs # run like so: nohup ./ddkclone.sh <src> <dst> <log> & # that will make a nohup.out file where your at, you can monitor the copy with: tail -f nohup.out # cancel monitoring with CONTROL-C and it will still run. # To kill the clone you will need to "killall ddrescue" two times # or maybe even superkill with "killall -9 ddrescue" # if you dont have killall then find the PID with "ps aux" and "kill <PID>" # or superkill with "kill -9 <PID>" #### ERROR: #### Note if you get the error: #### ddrescue: Output file exists and is not a regular file. #### ddrescue: Use '--force' if you really want to overwrite it, but be #### aware that all existing data in the output file will be lost. #### SOLUTION TO ERROR: #### Then change 2 lines: #### (STEP 1) #### add the letter f before the n and after the - in the 1st ddrescue line #### CHANGE THIS: #### ddrescue -n ${SRC123} ${DST123} ${LOG123} #### TO THIS: #### ddrescue -fn ${SRC123} ${DST123} ${LOG123} #### (STEP 2) #### add the letter f before r and after the - in the 2nd ddrescue line #### CHANGE THIS: #### ddrescue -r1 ${SRC123} ${DST123} ${LOG123} #### TO THIS: #### ddrescue -fr1 ${SRC123} ${DST123} ${LOG123} #### OTHER SOLUTION: is to use the force variable #### JUST STICK TO THE force VARIABLE, read the comment inline to see how to use it SRC123=$1 DST123=$2 LOG123=$3 force="" # LEAVE THIS ONE ALONE # force="-f" # REMOVE COMMENT IF IT CRIES ABOUT not regular file STARTTIME=`date` echo "===========${STARTTIME}=========== start good part clone src ${SRC123}, dst ${DST123}=================" echo "=====LOGGING WITH: ${LOG123}=====" ddrescue ${force} -n ${SRC123} ${DST123} ${LOG123} MIDTIME=`date` echo "===========${MIDTIME}=========== stop good part clone src ${SRC123}, dst ${DST123}=================" echo "===========${MIDTIME}=========== start bad part clone src ${SRC123}, dst ${DST123}==================" echo "=====LOGGING WITH: ${LOG123}=====" ddrescue ${force} -r1 ${SRC123} ${DST123} ${LOG123} echo "===========${ENDTIME}=========== stop bad part clone src ${SRC123}, dst ${DST123}==================" ENDTIME=`date` echo "START TIME : ${STARTTIME}" echo "MID TIME : ${MIDTIME}" echo "END TIME : ${ENDTIME}" echo "LOGGED WITH: ${LOG123}"