#!/bin/sh # Begin dd_rhelp # Copyright (C) 2004 LAB Valentin # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # TODO : # # # x Add a feature that if a log file is not found and the dest file has data throws an error or a warning... or something # # x - close parts should be joined by testing gaps between them... # x - BUG : show_bar doesn't correctly draw end of bar when a correct EOF is # found. (done ?) # x - found which is the correct EOF in log. (done ?) # x - Tests and ensures that nb_err is greater than 1. # x - First time it is launched, checks right and left limits of chunks. # x - Make a estimation time of end. Worse and good. # x - Test if dd_rescue is the good version : the one that makes a summary # even in maxerr mode (partly done...) # x - less but clearer output if possible (ansi color ?) # x - Real handling of options... for max_err min_bs max_bs, the log_file # source... etc ... # x - Much cleaner code. # x - Better internal Map, with dd_rescued byte, error bytes, clean bytes... # # === Do not touch these vars, they are compiled at 'configure' time. # # THIS CODE IS OBSOLETE : PROGRAMS PATHS ARE COMPUTED AT RUNTIME. # --- # Where to find programs #SED="@SED@" #GREP="@GREP@" #CAT="@CAT@" #CUT="@CUT@" #TR="@TR@" #HEAD="@HEAD@" #TAIL="@TAIL@" #TOUCH="@TOUCH@" #WC="@WC@" #BC="@BC@" # --- # Some info email="vaab@free.fr" version="0.0.6" state="beta" author="LAB Valentin" # Including 'libcolor.sh' # If COLUMNS hasn't been set yet (bash sets it but not when called as # sh), do it ourself if [ -z "$COLUMNS" ] then # Get the console device if we don't have it already # This is ok by the FHS as there is a fallback if # /usr/bin/tty isn't available, for example at bootup. test -x /usr/bin/tty && CONSOLE=`/usr/bin/tty` test -z "$CONSOLE" && CONSOLE=/dev/console # Get the console size (rows columns) stty size > /dev/null 2>&1 if [ "$?" == 0 ] then [ "$CONSOLE" == "/dev/console" ] && SIZE=$(stty size < $CONSOLE) \ || SIZE=$(stty size) # Strip off the rows leaving the columns COLUMNS=${SIZE#*\ } else COLUMNS=80 fi fi COL=$[$COLUMNS - 10] WCOL=$[$COLUMNS - 30] SCOL=$[$COLUMNS - 4] LCOL=$[$COLUMNS - 1] SET_COL=$(echo -en "\\033[${COL}G") SET_SCOL=$(echo -en "\\033[${SCOL}G") SET_WCOL=$(echo -en "\\033[${WCOL}G") SET_LCOL=$(echo -en "\\033[${LCOL}G") SET_BEGINCOL=$(echo -en "\\033[0G") NORMAL=$(echo -en "\\033[0;37m") RED=$(echo -en "\\033[1;31m") GREEN=$(echo -en "\\033[1;32m") YELLOW=$(echo -en "\\033[1;33m") BLUE=$(echo -en "\\033[1;34m") GRAY=$(echo -en "\\033[1;30m") WHITE=$(echo -en "\\033[1;37m") SUCCESS=$GREEN WARNING=$YELLOW FAILURE=$RED NOOP=$BLUE ON=$SUCCESS OFF=$FAILURE ERROR=$FAILURE # Including 'libcommon.sh' # DEPEND on libcolor [ -n "$exname" ] || exname=$(basename $0) function print_exit() { echo $@; exit 1; }; function print_syntax_error() { [ "$*" ] || print_syntax_error "$FUNCNAME: no arguments" print_exit "${ERROR}script error:${NORMAL} $@"; }; function print_syntax_warning() { [ "$*" ] || print_syntax_error "$FUNCNAME: no arguments."; [ "$exname" ] || print_syntax_error "$FUNCNAME: 'exname' var is null or not defined."; echo "$exname: ${WARNING}script warning:${NORMAL} $@"; }; function print_error() { [ "$*" ] || print_syntax_warning "$FUNCNAME: no arguments."; [ "$exname" ] || print_exit "$FUNCNAME: 'exname' var is null or not defined."; print_exit "$exname: ${ERROR}error:${NORMAL} $@" }; function print_warning() { [ "$*" ] || print_syntax_warning "$FUNCNAME: no arguments."; [ "$exname" ] || print_syntax_error "$FUNCNAME: 'exname' var is null or not defined."; echo "$exname: ${WARNING}warning:${WARNING} $@" }; function print_usage() { [ "$usage" ] || print_error "$FUNCNAME: 'usage' variable is not set or empty." echo "usage: $usage" # if [ "$_options" != "" ] # then # fi } function invert_list() { newlist=" " for i in $* do newlist=" $i${newlist}" done echo $newlist; }; function depends() { for i in $@ do if ! type $i > /dev/null 2>&1 then print_error "dependency check : couldn't find '$i' command." fi done } function require() { for i in $@ do if ! type $i > /dev/null 2>&1 then return 1; fi done } function print_octets () { [ "$*" ] || print_syntax_error "$FUNCNAME: no arguments."; [ "$2" ] && print_syntax_error "$FUNCNAME: too much arguments."; [ "$( echo "$1 < 1024" | bc )" == "1" ] && { echo -n "$1 octets"; return 0;} kbytes=$(echo "$1 / 1024" | bc ); [ "$( echo "$kbytes < 1024" | bc)" == "1" ] && { echo -n "$kbytes Ko" ; return 0; } mbytes=$(echo "$kbytes / 1024" | bc ); [ "$( echo "$mbytes < 1024" | bc)" == "1" ] && { echo -n "$mbytes Mo" ; return 0; } gbytes=$(echo "$mbytes / 1024" | bc ); [ "$( echo "$gbytes < 1024" | bc )" == "1" ] && { echo -n "$gbytes Go" ; return 0; } tbytes=$(echo "$gbytes / 1024" | bc ); echo -n "$gbytes To" } function checkfile () { [ "$*" ] || print_syntax_error "$FUNCNAME: no arguments."; [ "$3" ] && print_syntax_error "$FUNCNAME: too much arguments."; for i in $(echo $1 | sed 's/\(.\)/ \1/g') do case "$i" in "") : ;; "e") if ! [ -e "$2" ] then echo "'$2' is not found." return 1 fi;; "f") if ! [ -f "$2" ] then echo "'$2' is not a regular file." return 1 fi;; "d") if ! [ -d "$2" ] then echo "'$2' is not a directory." return 1 fi;; "r") if ! [ -r "$2" ] then echo "'$2' is not readable." return 1 fi;; "w") if ! [ -w "$2" ] then echo "'$2' is not writable." return 1 fi;; "x") if ! [ -x "$2" ] then echo "'$2' is not executable/openable." return 1 fi;; "l") if ! [ -L "$2" ] then echo "'$2' is not a symbolic link." return 1 fi;; esac done return 0; }; # === VARS : # # Feel free to change them. max_err=5 # number of error to start a new chunk # DO NOT SET TO "1"... min_bs=512 # min block size (see dd_rescue's help) max_bs=16384 # max block size (see dd_rescue's help) bar_lines=15 # nb of lines for bar drawing. # === CODE : # # function get_path { echo $(type -p $1) } function require_exe { path=$(get_path $1) if test -z "$path" ; then print_error "requires '$1' to run... And it couldn't find it." >&2 exit 1 else echo $path fi } # checks each required program and get their path. SED=$(require_exe sed) || exit 1 GREP=$(require_exe grep) || exit 1 CAT=$(require_exe cat) || exit 1 CUT=$(require_exe cut) || exit 1 TR=$(require_exe tr) || exit 1 HEAD=$(require_exe head) || exit 1 TAIL=$(require_exe tail) || exit 1 TOUCH=$(require_exe touch) || exit 1 WC=$(require_exe wc) || exit 1 BC=$(require_exe bc) || exit 1 tr=$(require_exe tr) || exit 1 # usage string : usage="$exname {filename|device} {output-file} [{info}] or $exname --help or $exname --version" # # === Argument checking... # if [ "$#" == "1" ]; then if [ "$1" == "--help" ]; then print_usage "${CAT}" <.log'. This is a dd_rescue log file (which is human readable). This log file is important as dd_rhelp feeds itself with its contents to manage correctly dd_rescue. Send bug reports, or comments to $email. Sorry for the shitty programming style. EOF exit fi if [ "$1" == "--version" ] ; then "${CAT}" < /dev/null 2>&1 then if ! "${TOUCH}" "$outfile" > /dev/null 2>&1 then print_error "'$outfile' is not accessible/could not be created..." else [ "$DEBUG" == "on" ] && echo "- file '$outfile' was successfully touched..." fi fi if ! checkfile erw "$logfile" > /dev/null 2>&1 then if [ "$opt" == "info" ] && ! [ -r "$logfile" ] then "${CAT}" < /dev/null 2>&1 then print_error "'$logfile' is not accessible/could not be created..." else [ "$DEBUG" == "on" ] && echo "- file '$logfile' was successfully touched..." fi else if [ "$opt" == "info" ] && [ "$(${CAT} "$logfile" | grep -v ^\$ )" == "" ] ; then "${CAT}" <&2 path=$(get_path dd_rescue) version=$("$path" -V 2>&1 | grep "dd_rescue Version" | cut -f 3 -d " " | cut -f 1 -d ",") [ "$DEBUG" == "on" ] && echo -n "Trying '$path' : gives this version : '$version'..." >&2 if is_num "$version" && [ "$(bc_calc 2 "$version < 1.03")" == "0" ] then [ "$DEBUG" == "on" ] && echo "OK !" >&2 echo "$path" return 0 else [ "$DEBUG" == "on" ] && echo "BAD !" >&2 fi path="$(dirname $(type -ap "$0" | "${TAIL}" -1))/dd_rescue" if [ -x "$path" ] ;then version=$("$path" -V 2>&1 | grep "dd_rescue Version" | cut -f 3 -d " " | cut -f 1 -d ",") [ "$DEBUG" == "on" ] && echo -n "Trying '$path' : gives this version : '$version'..." >&2 if is_num "$version" && [ "$(bc_calc 2 "$version < 1.03")" == "0" ];then [ "$DEBUG" == "on" ] && echo "OK !" >&2 echo "$path" return 0 else [ "$DEBUG" == "on" ] && echo "BAD !" >&2 fi fi echo "Bad version of dd_rescue ! you must have >= 1.03">&2 exit 1 }; # *** check whether $1 is num... # args : # $1 is string to be tested as num # returns errorlevel 0/1 depending on "$1" # std_out : nothing function is_num () { rest=$(echo $1 | sed 's/^\([0-9]\+\)\?\(\.\([0-9]\+\)\)\?$/X/g') if [ -z "$(echo $1 | grep '^\([0-9]\+\)\?\(\.\([0-9]\+\)\)\?$')" ] ;then return 1 else return 0 fi } # *** Handles BC conveniently # args : # $1 is scale (number of digit in result after '.') # $2+ is expression to be parsed by bc # returns : errorlevel 0 if no error occured # std_out : output of bc # quits program with errorlevel 1 if error occured # and output a debug string. function bc_calc () { scale=$1; if ! is_num "$scale" && test "$scale" != "no"; then echo "*** bc_calc: Wrong first argument " >&2 echo "*** '$scale' is not a number." >&2 exit 1 fi test "$scale" == "no" && scale="" shift exp=$(test "$scale" && echo "scale=$scale;"; test "$*" && echo "$*" || "${CAT}" - ) ans=$(echo "$exp" | "${BC}" 2>&1) if ! is_num "$ans"; then echo "*** BC failed on this expression : " >&2 echo "$exp" >&2 echo "*** BC returned :" >&2 echo "$ans" >&2 exit 1; else echo "$ans" return 0 fi } # Go fetch EOF information in log to get a good approximation # no args # Depends on content of logfile. # errorlevel allways 0 # return nothing # changes $eof to "nothing" if no EOF is found, # or 'nb' where nb is best EOF found function get_eof() { eoflines="$("${CAT}" "$logfile" | "$tr" -d "\\r" | "$GREP" "$eofstring" | "$SED" 's/^dd_rescue: (info): .* (\([0-9\.]\+\)k): EOF$/\1/g')" eof="nothing" for i in $eoflines do if [ "$eof" == "nothing" ]; then eof=$i continue fi if [ "$(bc_calc 1 "$eof > $i")" == "1" ];then eof=$i continue fi done } # Will mark chunk as beiing completed # Depends on '$chunk', $chunk MUST be correctly generated !! # args : # "nb1-nb2" with nb1 $i_stop" )" if [ "$as_gt_ie" == "1" ] then # new chunk doesn't overlap with current chunk # Iterate, put current chunk in $goodchunk. goodchunk="$(echo -en "$goodchunk\n$i")" parsechunk="$(echo "$parsechunk" | "${TAIL}" +2)" continue fi # new chunk ends before current chunk start ? ae_gt_is="$(bc_calc 1 "$arg_stop < $i_start")" if [ "$ae_gt_is" == "1" ] then # new chunk doesn't overlap with current chunk but is before # we have found where to put our chunk break; # we can break because chunk are sorted fi # if we come here, that means that new chunk overlap with current. # have we new chunk's start located IN current chunk ? as_int="$(bc_calc 1 "$arg_start >= $i_start && $arg_start <= $i_stop")" # have we new chunk's end located IN current chunk ? ae_int="$(bc_calc 1 "$arg_stop >= $i_start && $arg_stop <= $i_stop ")" # new chunk is contained entirely in current chunk if [ "$as_int" == "1" ] && [ "$ae_int" == "1" ] then # no need to do anything overlap="yes" break; fi # new chunk contains entirely current chunk if [ "$as_int" == "0" ] && [ "$ae_int" == "0" ] then # we forget about current chunk, and iterate. parsechunk=$(echo "$parsechunk" | "${TAIL}" +2) continue fi # new chunk overlap on its end with beginning of current chunk if [ "$as_int" == "0" ] && [ "$ae_int" == "1" ] then # grow new chunk to englobe current chunk. arg_stop=$i_stop parsechunk=$(echo "$parsechunk" | "${TAIL}" +2) break; # we can break because chunk are sorted. fi # new chunk overlap on its beginning with end of current chunk if [ "$as_int" == "1" ] && [ "$ae_int" == "0" ] then # grow new chunk to englobe current chunk. arg_start=$i_start parsechunk=$(echo "$parsechunk" | "${TAIL}" +2) continue; # new chunk might overlap more chunks fi done # Overlapping occurs only if new chunk is contained in already marked # chunk. In this case, we musn't change $chunk. if [ "$overlap" == "no" ] then chunk="$(echo -en "$goodchunk\n$arg_start-$arg_stop\n$parsechunk" | "$GREP" -v ^\$)" fi } # get_next_pos will found the next offset to jump at to launch dd_rescue # No args # depends on $eof # returns offset:long (offset in start location, long is how much bytes # to retrieve from location both reverse and forth) function get_next_pos() { if [ "$eof" == "nothing" ] || test -z "$eof" then # finding last's chunk end. if test "$chunk" ;then last_chunk=$(echo "$chunk" | "${TAIL}" -1 ) max_stop=$(echo "$last_chunk" | "${CUT}" -f 2 -d "-") else max_stop=0 fi echo "$(bc_calc 1 "($max_stop * 2)"):$max_stop"; else # find biggest hole. pos=0 size=0 cursize=0 start=0 next=0 # Get biggest hole between chunks for i in $chunk "$eof-$eof" do # collect start of chunk next=$(echo "$i" | "${CUT}" -f 1 -d "-") if [ "$next" != "$start" ] then cursize="$(bc_calc 1 "($next - $start)")" if [ "$(bc_calc 1 "($size < $cursize)")" == "1" ] then size=$cursize pos=$start fi fi start=$(echo "$i" | "${CUT}" -f 2 -d "-") done size="$(bc_calc 0 "(($size + 1) / 2)")" echo "$(bc_calc 1 "($pos + $size)"):$size" fi } # Get info with last summary produced by dd_rescue call. # no args # depends on content of log file # changes $logcontent, $chunk, $eof function swallow_last_summary() { # last summary of log (4 lines output by printreport()) last_logcontent=$("${CAT}" "$logfile" | "$tr" -d "\\r" | "$GREP" "$string" -A 3 | "${TAIL}" -4) process_log "$last_logcontent" get_eof save_log } function get_last_chunk() { if test "$chunk"; then last_chunk="$(echo "$chunk" | "${TAIL}" -1 )" echo "$last_chunk" | "${CUT}" -f 2 -d "-" else echo 0 fi }; # Display a neat bar in ascii art(?!) which shows completion of dd_rescue. # # # function show_bar() { echo "=== BAR === [ 'x' dd_rescued, '*' next jump point, '|' '.' not dd_rescued ]" if [ "$eof" == "nothing" ] || test -z "$eof" then eof_limit="$(get_last_chunk)" next_pos="$(get_next_pos | "${CUT}" -f 1 -d ":")" if [ "$(bc_calc 1 "$eof_limit < $next_pos")" == "1" ]; then eof_limit=$next_pos fi else eof_limit="$eof"; fi if ! is_num "$nb_stars";then nb_stars=80 fi if [ "$eof_limit" != "0" ] then # c_res is nb of Kb represented by one char. c_res="$(bc_calc 10 "$eof_limit / $nb_stars")"; # next_pos is place of next jump in chars. next_pos="$(bc_calc 0 "$(get_next_pos | "${CUT}" -f 1 -d ":") / $c_res")"; # echo -n "["; curchar=0 start=0 next=0 ct=0 for i in $chunk $eof_limit-$eof_limit do start=$(echo "$i" | "${CUT}" -f 1 -d "-") if [ "$next" != "$start" ] then # This is start of hole startchar="$(bc_calc 0 "$next / $c_res")" # This is end of hole curchar="$(bc_calc 0 "$start / $c_res")" # draw completed chars up to start of hole. while [ "$ct" -lt "$startchar" ] ;do echo -n "x" ct=$[$ct+1] ; done # our current tracker ($ct) is now at : $ct==$startchar # OR is $ct = $startchar + 1 ONLY if precedent hole finished # in the same char this hole begins !! # as rounding occurs, we might have $startchar == $curchar # but original hole is not null ! We must show that there's # a hole in this char. # hole is bigger than 1 char if [ "$startchar" -lt "$curchar" ] ; then # if current drawing position ($ct) is on startchar if [ "$ct" == "$startchar" ] ;then # draw the beginning of hole. [ "$ct" != "$next_pos" ] && echo -n "|" || echo -n "*" ct=$[$ct + 1] fi # mark char between startchar and curchar as hole. while [ "$ct" -lt "$curchar" ] ; do [ "$ct" != "$next_pos" ] && echo -n "." || echo -n "*" ct=$[$ct + 1] done # current tracker is now equal to curchar. # draw the end of hole. if [ "$nb_stars" -gt "$curchar" ] ; then [ "$ct" != "$next_pos" ] && echo -n "|" || echo -n "*" ct=$[$ct + 1] fi else # the only remaining possibility is that $startchar=$curchar # this is the rounding possibility. # if [ "$startchar" == "$curchar" ] ; then if [ "$nb_stars" -gt "$curchar" ] ; then if [ "$ct" == "$next_pos" ] ; then [ "$ct" != "$next_pos" ] && echo -n "|" || echo -n "*" ct=$[$ct + 1] fi fi # fi fi else if [ "$start" == "$eof_limit" ]; then while [ "$ct" -lt "$nb_stars" ] ;do echo -n "x" ct=$[$ct+1] ; done fi fi next=$(echo "$i" | "${CUT}" -f 2 -d "-") done else echo -n "[ No Bar available the first launch ]" fi last_chunk="$(get_last_chunk)" if [ "$eof_limit" != "$last_chunk" ] then echo "=== Bar was drawn from 0 to hypothetic end : $eof_limit" else echo "=== Bar was drawn from 0 to $eof_limit" fi } function show_info() { echo "=== dd_rhelp INFO -" $(echo "$chunk" | "${WC}" -l) "chunks..."; jump=$(get_next_pos | "${CUT}" -f 1 -d ":") [ "$jump" != "0" ] && echo -n "- Jump pos : $(get_next_pos | "${CUT}" -f 1 -d ":") " if [ "$eof" == "nothing" ] then echo "- max file size : no limit found" else echo "- max file size : $eof" echo -en "- Biggest hole size : " "$(bc_calc 1 "$(get_next_pos | "${CUT}" -f 2 -d ":") * 2")" "k " fi parsing="$logcontent" total_errxfer="0"; total_succxfer="0"; total_xferd="0"; while test "$parsing" do firstline="$(echo "$parsing" | "${HEAD}" -1)" parsing="$(echo "$parsing" | "${TAIL}" +2)" xferd="$(echo "$firstline" | "${CUT}" -f 2 -d ":" | "${CUT}" -f 2 -d "=")" errxfer="$(echo "$firstline" | "${CUT}" -f 4 -d ":" | "${CUT}" -f 2 -d "=")" succxfer="$(echo "$firstline" | "${CUT}" -f 5 -d ":" | "${CUT}" -f 2 -d "=")" total_errxfer="$(bc_calc 1 "$total_errxfer + $errxfer")" total_succxfer="$(bc_calc 1 "$total_succxfer + $succxfer")" total_xferd="$(bc_calc 1 "$total_xferd + $xferd")" done size=0 cursize=0 start=0 next=0 for i in $chunk do next=$(echo "$i" | "${CUT}" -f 1 -d "-") if [ "$next" != "$start" ] then cursize="$(bc_calc 1 "$next - $start")" size="$(bc_calc 1 "$size + $cursize")" fi start=$(echo "$i" | "${CUT}" -f 2 -d "-") done echo -e "- total holes : ${size}k" echo -e "- xferd(succ/err) : ${total_xferd}k(${total_succxfer}k/${total_errxfer}k)" eof_limit=$(get_last_chunk) echo -en "- EOF " if [ "$eof" != "nothing" ] && [ "$eof" == "$eof_limit" ];then echo "is found and is at ${eof}k." else if [ "$eof" != "nothing" ]; then echo "is not found, but between ${eof_limit}k and ${eof}k." else echo "is not found, but greater than ${eof_limit}k" fi fi if [ "$size" == "0" ] && [ "$eof" != "nothing" ] && [ "$eof" == "$eof_limit" ];then return 0 else return 1 fi } function process_log() { data="$1" test -z data && return 0 [ "$DEBUG" == "on" ] && echo -n "- cleaning data [" data=$(echo "$data" | "$GREP" -v "xferd: \+0.0k$") [ "$DEBUG" == "on" ] && echo -n "." data=$(echo "$data" | "$GREP" "$infoline" -A 1 | "${CUT}" -c 12-) [ "$DEBUG" == "on" ] && echo -n "." data=$(echo "$data" | "$SED" 's/^(info): ipos: \+//g') [ "$DEBUG" == "on" ] && echo -n "." data=$(echo "$data" | "$SED" 's/^ \+errs: \+/NR:/g') [ "$DEBUG" == "on" ] && echo -n "." data=$(echo "$data" | "$SED" 's/^ \+- \+errs: \+/RE:/g') [ "$DEBUG" == "on" ] && echo -n "." data=$(echo "$data" | "$SED" 's/^\([0-9\.]\+\)k, opos:.\+xferd: \+\([0-9\.]\+\)k$/ipos=\1:xferd=\2:/g') [ "$DEBUG" == "on" ] && echo -n "." data=$(echo "$data" | "$SED" 's/^\(RE\|NR\):[0-9]\+, errxfer: \+\([0-9\.]\+\)k, succxfer: \+\([0-9\.]\+\)k$/\1:errxfer=\2:succxfer=\3;/g') [ "$DEBUG" == "on" ] && echo -n "." data=$(echo "$data" | "${TR}" -d "\n") [ "$DEBUG" == "on" ] && echo -n "." data=$(echo "$data" | "${TR}" ";" "\n") [ "$DEBUG" == "on" ] && echo ".]" # All info now take one line per entry, and field are separated by ":" [ "$DEBUG" == "on" ] && echo -n "- processing data [" # finding start of chunks parsing="$data" # chunk="" while test "$parsing" ;do firstline="$(echo "$parsing" | "${HEAD}" -1)" parsing="$(echo "$parsing" | "${TAIL}" +2)" ipos="$(echo $firstline | "${CUT}" -f 1 -d ":" | "${CUT}" -f 2 -d "=")" xferd="$(echo $firstline | "${CUT}" -f 2 -d ":" | "${CUT}" -f 2 -d "=")" rev="$(echo $firstline | "${CUT}" -f 3 -d ":")" errxfer="$(echo $firstline | "${CUT}" -f 4 -d ":" | "${CUT}" -f 2 -d "=")" succxfer="$(echo $firstline | "${CUT}" -f 5 -d ":" | "${CUT}" -f 2 -d "=")" if [ "$rev" == "RE" ] ; then start="$ipos" stop="$(bc_calc 1 "$ipos + $xferd")" else start="$(bc_calc 1 "$ipos - $xferd")" stop="$ipos" fi chunkline="$start-$stop" add_chunk $chunkline [ "$DEBUG" == "on" ] && echo -n "." done [ "$DEBUG" == "on" ] && echo "]"; if test "$logcontent";then logcontent="$(echo -en "$logcontent\n$data")" else logcontent="$data"; fi } function load_log() { # # loading into memory Summary info found in log file... # # line number of last save_log entry... lnb_save=$("${CAT}" -n "$logfile" | "$tr" -d "\\r" | grep "chunk:" -A 2 | "${TAIL}" -3) if test "$lnb_save" ;then lnb_save=$(echo $lnb_save | "${HEAD}" -1 | cut -f 1 -d " ") end_log="$(cat "$logfile" | "$tr" -d "\\r" | "${TAIL}" "+$lnb_save")" last_lines=$(echo "$end_log" | grep "chunk:" -A 2 | "${TAIL}" -3) log=$(echo "$last_lines" | "$GREP" "chunk" | "${TAIL}" -1 ) log1=$(echo "$last_lines" | "$GREP" "logcontent" | "${TAIL}" -1 ) log2=$(echo "$last_lines" | "$GREP" "eof" | "${TAIL}" -1 ) if test "$log" && test "$log1" && test "$log2" ;then chunk="$(echo "$log" | "${CUT}" -f 2- -d ":" | "${TR}" ":" "\n")" logcontent="$(echo "$log1" | "${CUT}" -f 2- -d : | "${TR}" ";" "\n")" eof="$(echo "$log2" | "${CUT}" -f 2 -d ":")" log=$(echo "$end_log" | "$GREP" "$string" -A 3 ) process_log "$log" return 0 else echo "Bad log format !!! Fallback to slow mode..." fi fi # select all summary info of dd_rescue log=$("${CAT}" "$logfile" | "$tr" -d "\\r" | "$GREP" "$string" -A 3 ) # Set EOF with log. get_eof # Sets logcontent AND chunk process_log "$log" } function save_log() { echo "=== COMPUTED VERSION OF LOG :" >> "$logfile" echo "chunk:$(echo -n "$chunk" | "${TR}" "\n" : )" >> "$logfile" echo "logcontent:$(echo -n "$logcontent" | "${TR}" "\n" ";" )" >> "$logfile" echo "eof:$eof" >> "$logfile" } # === beginning of real code load_log # Save computed version of log for next time. save_log if [ "$opt" == "info" ] && test -z "$logcontent" then echo "No Info found in log..." exit 0; fi if [ "$opt" != "info" ];then DD_RESCUE="$(get_valid_dd_rescue)" [ "$?" != "0" ] && exit 1 else echo "$(show_info)" if [ "$?" == "0" ] ; then echo "ALL your data has been dd_rescued !!" else show_bar fi exit 0 fi while [ "$(echo "$chunk" | "${WC}" -l)" != "1" ] || [ "$(get_last_chunk)" != "$eof" ] || [ "$eof" == "nothing" ] do info="$(show_info)" if [ "$?" == "0" ] ; then echo "$info" echo "ALL your data has been dd_rescued !!" # show_bar exit 0 fi if [ "$logcontent" != "" ] ;then echo "$info"; show_bar fi [ "$DEBUG" == "on" ] && [ "$opt" == "info" ] && [ "$chunk" != "" ] && echo -en "Chunks that were dd_rescued (in k):\ \n$chunk\n" [ "$opt" == "info" ] && exit 1; next_pos="$(get_next_pos | "${CUT}" -f 1 -d ":")k" count="$(get_next_pos | "${CUT}" -f 2 -d ":")k" if [ "$next_pos" != "0k" ] then echo "=== launched via '$exname' at $next_pos, $count <<< ===" >> "$logfile" echo "=== launched via '$exname' at $next_pos, $count <<< ===" ${DD_RESCUE} -r -s "$next_pos" -l "$logfile" -e "$max_err" -B "$min_bs" -b "$max_bs" -m "$count" "$infile" "$outfile" swallow_last_summary fi if [ "$next_pos" != "${eof}k" ] then if [ "$eof" == "nothing" ] then count=0; fi echo "=== launched via '$exname' at $next_pos, $count >>> ===" >> "$logfile" echo "=== launched via '$exname' at $next_pos, $count >>> ===" ${DD_RESCUE} -s "$next_pos" -l "$logfile" -e "$max_err" -B "$min_bs" -b "$max_bs" -m "$count" "$infile" "$outfile" swallow_last_summary fi done # End dd_rhelp