home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 2007 January, February, March & April
/
Chip-Cover-CD-2007-02.iso
/
boot
/
i386
/
rescue
/
bin
/
dd_rhelp
< prev
next >
Wrap
Text File
|
2006-11-29
|
31KB
|
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