home *** CD-ROM | disk | FTP | other *** search
Text File | 2006-11-29 | 29.8 KB | 1,242 lines |
- #!/bin/sh
- # Begin dd_rhelp
- # Copyright (C) 2004 LAB Valentin <vaab@free.fr>
- #
- # 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}" <<EOF
-
- Options:
- --help Print this message
- --version Print version information
- {filename|device} The source file (it can be a block device)
- {output-file} The destination file
- info Specifying "info" as third argument will display
- summary informations on ongoing recovery and
- exit without taking any actions.
-
- Note:
- A log file will be created, and named '<output-file>.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}" <<EOF
- $exname $version ($state)
- EOF
- exit
- fi
-
- echo "Need 2 arguments..."
- print_usage
- exit 1
- fi
-
-
-
- if [ "$1" == "" ]
- then
- echo "Need 2 arguments..."
- print_usage
- exit 1;
- fi
-
- if [ "$3" != "" ] && [ "$3" != "info" ]
- then
- shift;shift
- echo "too much argument... : '$*' is beyond limit. "
- print_usage
- exit 1;
- fi
-
- if [ "$3" == "info" ]
- then
- opt="info"
- fi
-
- infile="$1"
- outfile="$2"
- logfile="$2.log"
-
- #
- # === Files checking
- #
-
-
- if ! checkfile er "$infile"
- then
- print_error "'$infile' is not accessible..."
- exit 1;
- fi
-
- if ! checkfile erw "$outfile" > /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}" <<EOF
- No info available since there's no readable '$logfile'.
-
- 'info' option outputs information on current rescuing state by parsing this
- log file that would have been created by a precedent use of dd_rhelp or
- dd_rescue. Since there's no log file, it has nothing to display.
-
- This happens if you haven't launched a dd_rhelp before.
- EOF
- exit 0 ;
- fi
-
-
-
- if ! "${TOUCH}" "$logfile" > /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}" <<EOF
- No info available in '$logfile' : it is empty !
-
- 'info' option outputs information on current rescuing state by parsing this
- log file that would have been created by a precedent use of dd_rhelp or
- dd_rescue. Since there's no content in log file, it has nothing to display.
-
- This could happens if you haven't launched a dd_rhelp before.
- EOF
- exit 0 ;
- fi
-
- fi
-
-
- #
- # === Some vars, do not touch unless you know what you are doing...
- #
-
- # regexp for parsing the log file.
-
- string="^Summary for $infile -> $outfile:"
- infoline="^dd_rescue: (info):"
- eofstring="$infoline $infile ([0-9]\+\.[0-9]k): EOF\$"
- nb_stars=$[ $bar_lines * $COLUMNS ] # nb of char to display progress bar...
-
- #
- # === Functions
- #
-
- # Variable that holds chunks info in a list of
- # lines of nb1-nb2...
- chunk=""
-
-
-
- function get_valid_dd_rescue
- {
-
- [ "$DEBUG" == "on" ] && echo "Finding dd_rescue binary" >&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
- if [ "$(bc_calc 2 "$version < 1.12")" == "0" ]
- then
- echo "$path -y0"
- else
- echo "$path"
- fi
- return 0
- else
- [ "$DEBUG" == "on" ] && echo "BAD !" >&2
- fi
-
- path="$(dirname $(type -ap "$0" | "${TAIL}" -n 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<nb2
- # Modifies '$chunk'.
- function add_chunk()
- {
- arg_start=$(echo "$1" | "${CUT}" -f 1 -d "-")
- arg_stop=$(echo "$1" | "${CUT}" -f 2 -d "-")
-
- if ! is_num "$arg_start" ||
- ! is_num "$arg_stop"; then
- print_error "*** add_chunk : invalid argument '$1' (is not correctly formatted as number:number)"
- fi
-
- if test "$(bc_calc 1 "$arg_start < $arg_stop")" == "0"; then
- print_error "*** add_chunk : invalid argument '$1' (these are not logical values)"
- fi
-
- overlap="no"
-
- goodchunk=""
- parsechunk="$chunk"
-
- while test "$parsechunk"
- do
-
- # get first chunk already marked.
- i="$(echo "$parsechunk" | "${HEAD}" -n 1 )"
-
- # pull the two bounds
- i_start="$(echo "$i" | "${CUT}" -f 1 -d "-")"
- i_stop="$(echo "$i" | "${CUT}" -f 2 -d "-")"
-
-
- # new chunk begins after current chunk end ?
- as_gt_ie="$(bc_calc 1 "$arg_start > $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}" -n +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}" -n +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}" -n +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}" -n +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}" -n 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}" -n 4)
- process_log "$last_logcontent"
-
- get_eof
-
- save_log
-
- }
-
-
-
- function get_last_chunk()
- {
- if test "$chunk"; then
- last_chunk="$(echo "$chunk" | "${TAIL}" -n 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}" -n 1)"
- parsing="$(echo "$parsing" | "${TAIL}" -n +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}" -n 1)"
- parsing="$(echo "$parsing" | "${TAIL}" -n +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}" -n 3)
-
-
- if test "$lnb_save" ;then
- lnb_save=$(echo $lnb_save | "${HEAD}" -n 1 | cut -f 1 -d " ")
-
- end_log="$(cat "$logfile" | "$tr" -d "\\r" | "${TAIL}" -n "+$lnb_save")"
-
- last_lines=$(echo "$end_log" | grep "chunk:" -A 2 | "${TAIL}" -n 3)
-
- log=$(echo "$last_lines" | "$GREP" "chunk" | "${TAIL}" -n 1 )
- log1=$(echo "$last_lines" | "$GREP" "logcontent" | "${TAIL}" -n 1 )
- log2=$(echo "$last_lines" | "$GREP" "eof" | "${TAIL}" -n 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
-