#! /bin/sh
#
#   copy.sh -- エラーを無視してデータをコピー
#
#	使い方: /bin/sh copy.sh コピー元ディスク コピー先ディスク
#		ディスク: デバイスファイルで指定、先頭の「/dev/」は省く
#		例: /bin/sh copy.sh ad0 ad1
#
#	0.0: Aug.  5, 2006 by Dai ISHIJIMA (for wpout07)
#	0.1: Feb. 10, 2007 (ログ記録 for wpout08)
#	0.2: Feb. 15, 2007 (エンターキー長押し対策)
#	0.3: Sep. 12, 2007 (wpout09)
#	0.4: Oct.  6, 2007 (expr(1) のPOSIX対応)
#	0.4: Dec. 13, 2007 (バーグラフ、残り所要時間のオーバーフロー修正)
#	0.5: Jan.  2, 2008 (ログ修正)
#	0.6: Apr. 19, 2009 (ブロックサイズ可変, wpout10)
#	0.7: Oct. 11, 2013 (コピー中のディスク名表示, wpout13)
#

ERRORLOG="${ERRORLOG:-/tmp/wperrlog.txt}"
exec 2>> $ERRORLOG
echo "# start $0, $@" 1>&2
echo '# ---------------------------- #' 1>&2

# 単独でも動くように
LOGFIL="${LOGFIL:-/tmp/wpoutlog.txt}"
DMESG="${DMESG:-/var/run/dmesg.boot}"
PATTERNFIL="${PATTERNFIL:-/tmp/pattern.dat}"
dispupd="${DISPUPD:-2}"

echo '# ---------------------------- #' >> $LOGFIL
echo -n "script $0 started on " >> $LOGFIL
date >> $LOGFIL

# 計算時に 32bit signed int の限界に引っかからないようにする
export EXPR_COMPAT

# ブロックサイズは512バイト
cbs="${CBS:-512}"

srcdisk="${1:-ad0}"
dstdisk="${2:-ad1}"
cbs="${3:-$cbs}"

dmesg="${DMESG:-/var/run/dmesg.boot}"

if [ ! -r /dev/$srcdisk ]; then
	echo "$0: disk '$srcdisk' does not exist or is not readable"
	echo "Usage: $0 srcdisk dstdist"
	exit 1
fi
if [ ! -w /dev/$dstdisk ]; then
	echo "$0: disk '$dstdisk' does not exist or is not writable"
	echo "Usage: $0 srcdisk dstdist"
	exit 1
fi

# 一度に32Mバイトずつ
blklen="${BLKLEN:-33554432}"

# コピーのパラメータ
# Mバイト単位で数える
mbytes=`disksize -m /dev/$srcdisk`
# 524288Mバイト以下ならブロックサイズは512バイト
# ブロック数のカウントが30ビットで収まるようにする
xbs=$(( ( $mbytes + 524288 - 1 ) / 524288 ))
minbs=512
xbs=$(( $xbs >> 1 ))
# ブロック長はディスクサイズに応じて 512, 1k, 2k, 4k,..
while [ $xbs -gt 0 ]; do
	minbs=$(( $minbs << 1 ))
	xbs=$(( $xbs >> 1 ))
done

# 指定ブロック長が短い (計算があふれる恐れのある) ときは長くする
if [ $cbs -lt $minbs ]; then
	cbs=$minbs
fi
ccnt=$(( $blklen / $cbs ))
#
obs="${OBS:-1048576}"
ocnt=$(( $blklen / $obs ))
ounit=$(( $obs / 1048576 ))


title="${TITLE:-ハードディスク消去ツール『wipe-out』}"

sname=`sed -n -E "/^${srcdisk}:.*<.*>/p" $dmesg | sed 's/.*\(<.*>\).*/\1/'`
sbytes=`disksize -B /dev/$srcdisk`
dname=`sed -n -E "/^${dstdisk}:.*<.*>/p" $dmesg | sed 's/.*\(<.*>\).*/\1/'`
dbytes=`disksize -B /dev/$dstdisk`

msg="ディスク ${srcdisk} ${sname} の\n"
msg="${msg}全データ ${sbytes}バイトを、${cbs}バイト単位で\n"
msg="${msg}ディスク ${dstdisk} ${dname}\n"
msg="${msg}(${dbytes}バイト) にコピーします。"
msg="${msg}\n                      よろしいですか?"

sh dummyread.sh
dialog --title "$title" --yesno "$msg" 9 64

case x"$?" in
	x1)
		dialog	--title "$title" \
			--infobox 'ディスクのコピーをキャンセルしました' 3 64
		sleep 2
		exit 1
		;;
esac


msg="本当に${srcdisk}のデータを${dstdisk}にコピーしていいですか?"

sh dummyread.sh
dialog	--title "$title" \
	--hline "$dname" \
	--yesno "$msg" \
	5 72

case x"$?" in
	x1)
		dialog	--title "$title" \
			--infobox 'ディスクのコピーをキャンセルしました' 3 64
		sleep 2
		exit 1
		;;
esac


dd if=/dev/$dstdisk ibs=512 count=1 | check -s 2>&1
case $? in
	0)
		dstempty="may be empty or erased."
		;;
	*)
		dstempty="may NOT be empty or erased."
		msg="コピー先のディスク${dstdisk} ${dname}\n"
		msg="${msg}にはデータが残っている可能性があります\n"
		msg="${msg}本当に${srcdisk}のデータを"
		msg="${msg}${dstdisk}にコピーしていいですか?"
		sh dummyread.sh
		dialog	--title "$title" \
			--hline "$dname" \
			--yesno "$msg" \
			7 72
		case x"$?" in
		x1)
			dialog	--title "$title" \
				--infobox \
				'ディスクのコピーをキャンセルしました' 3 64
			sleep 2
			exit 1
			;;
		esac
		;;
esac


ccnt=$(( $blklen / $cbs ))
max=$(( $mbytes * (1048576 / $cbs) ))

startsec=`tinydate '+%s'`
rems=''

#
echo "v ---------------------------- v" >> $LOGFIL
echo -n "copy started on " >> $LOGFIL
date >> $LOGFIL
echo "  copy $srcdisk ($sname)" >> $LOGFIL
echo "  -> $dstdisk ($dname)" >> $LOGFIL
echo "  destination disk $dstdisk ($dname) $dstempty" >> $LOGFIL
echo "  copying $sbytes bytes ($mbytes Mbytes)" >> $LOGFIL
echo "  cbs=$cbs, ccnt=$ccnt, max=$max, obs=$obs, ocnt=$ocnt" >> $LOGFIL

nerrs=0
skip=0
oseek=0
xcent=100
xmill=1000
mcent=$max
mmill=$max
if [ $max -gt 1048576 ]; then
	xcent=1
	xmill=1
	mcent=$(( ( $max + 99 ) / 100 ))
	mmill=$(( ( $max + 999 ) / 1000 ))
fi
#
echo "  xcent=$xcent, xmill=$xmill, mcent=$mcent, mmill=$mmill" >> $LOGFIL
lastdisp=0
dispintv=0
while [ $skip -le $max ]; do
	# 計時
	cursec=`tinydate '+%s'`
	# バーグラフ
	p=$(( ( $xcent * $skip ) / $mcent ))
	m=$(( ( $xmill * $skip ) / $mmill ))
	q=$(( $p / 2 ))
	i=0
	bar=''
	while [ $i -lt $q ]; do
		bar="$bar"'#'
		i=$(( $i + 1 ))
	done
	while [ $i -lt 50 ]; do
		bar="$bar"'_'
		i=$(( $i + 1 ))
	done
	# 残り時間
	elapsed=$(( $cursec - $startsec ))
	if [ $elapsed -gt 10 ]; then
		if [ $m -gt 0 ]; then
			remain=$(( ( 1000 - $m ) * $elapsed / $m + 1 ))
			if [ $remain -gt 120 ]; then
				rems=$(( ( $remain + 59 ) / 60 ))
				rems="残り およそ${rems}分"
			else
				rems="残り およそ${remain}秒"
			fi
		fi
	fi
	if [ $elapsed -gt 120 ]; then
		elas=$(( ( $elapsed + 30 ) / 60 ))
		elas="${elas}分"
	else
		elas="${elapsed}秒"
	fi
	#
	text="ディスク ${srcdisk} ${sname} の\n"
	text="${text}データを ${dstdisk} ${dname} に\n"
	text="${text}${cbs}バイト単位でコピーしています。\n"
	text="${text} ${p}% ($skip/$max) 終了 ／ "
	text="${text}${elas} 経過  ${rems}  \n\n"
	text="${text}        0%|${bar}|100%"
	text="${text}\n${errormsg}"
	dispintv=$(( $cursec - $lastdisp ))
	if [ $dispintv -ge $dispupd ]; then
		dialog --title "$title" --infobox "$text" 9 72
		lastdisp=$cursec
	else
		echo -e '\r\c'
	fi
	case "x$progchar" in
		xO) progchar='.' ;;
		xo) progchar='O' ;;
		*)  progchar='o' ;;
	esac
	echo -n "$progchar $status2"
	case x$DEBUG in
		x[Yy]*)
			status2='now in debug mode...'
			errormsg=''
			sleep 1
			;;
		*)
			status=`dd if=/dev/$srcdisk ibs=$cbs skip=$skip conv=noerror,sync obs=$obs seek=$oseek count=$ccnt of=/dev/$dstdisk 2>&1`
			status2=`echo "$status" | sed -n '/transfer/p'`
			errormsg=`echo "$status" | sed -n -E '/records (in|out)$/!p' | sed -n '/transferred in/!p'`
			;;
	esac
	# 記録
	case x"$skip" in
		x0)
			echo "skip: $skip, $status2" >> $LOGFIL
			;;
	esac
	case x"${nerrs}"x"${errormsg}" in
		x[0-8]x?*)
			echo "errmesg[${nerrs}]: $errormsg" >> $LOGFIL
			nerrs=$(( $nerrs + 1 ))
			;;
		x9x?*)
			echo "errmesg[${nerrs}]: $errormsg" >> $LOGFIL
			echo "Too many errors encounterd..." >> $LOGFIL
			nerrs=$(( $nerrs + 1 ))
			;;
	esac
	# 次ループ
	skip=$(( $skip + $ccnt ))
	oseek=$(( $oseek + $ocnt ))
done

sleep 2

#
echo "skip: $skip, $status2" >> $LOGFIL
echo "number of error messages: $nerrs" >> $LOGFIL
echo -n "copy finished on " >> $LOGFIL
date >> $LOGFIL
echo -n "$srcdisk ($sname, $sbytes)" >> $LOGFIL
echo "  -> $dstdisk ($dname, $dbytes)" >> $LOGFIL
echo "^ ---------------------------- ^" >> $LOGFIL

cursec=`tinydate '+%s'`
elapsed=$(( $cursec - $startsec ))
if [ $elapsed -gt 120 ]; then
	min=$(( $elapsed / 60 ))
	sec=$(( $elapsed - $min * 60 ))
	elas="${min}分${sec}秒"
else
	elas="${elapsed}秒"
fi

sh dummyread.sh
dialog	--title "$title" \
	--msgbox "ディスクのコピーが終了しました (${elas})" 5 72

#
echo '# ---------------------------- #' 1>&2

exit 0

# EOF
