プログラミングに関する私的メモ

LANDISK HDL-GS

最終更新:

匿名ユーザー

- view
だれでも歓迎! 編集

バグ?

 工場出荷時バージョンのファームウェア1.02から最新版1.15へアップデートすると、「デジカメコピー」と「iobb.net」の機能が増える。後者機能の初期値としてUPnP機能がONになっているのだが、ルーターがUPnPに応答しないとHDL-GSの電源ボタンで電源が切れないことがある。
 電源OFFシーケンス中にUPnPでルーターからグローバルIPアドレスを取得しようとするのだが、ルーターのUPnPは切ってあるのでそこで処理が止まるようだ。Webインタフェースが生きている場合はそちらから電源OFFを選べばいい。

tar2diskのパーティション割当サイズ

 新品のHDDをHDL-GSシステム用にするスクリプトが /boot/.landisk/tar2disk である。これは512バイト/セクタを前提としているので、4096バイト/物理セクタのHDDではいまいちよろしくない。実際、物理セクタ一つの破損で2パーティションが影響を受けた。
 というわけで、改良版tar2disk
#!/bin/sh
#
# tar2disk: tar ball をディスクに展開、指定によりパーティションを切る
# # 2017-04-26
# usage: tar2disk sda [reset|reset_full|none   [ignore_smart]] 
# sda means:
#	/dev/sda like that.
#	if it is hdb then it is internal HDD of normal configuration.
#	Others is external HDD.
# OPERATION: (option 'none' is default)
#	(none)	smart_check		(if ignore_smart, result ignore)
#	(none)	partition
#			mkswap
#			swapon			(if internal HDD)
#			trap swapoff	(if internal HDD)
#	--partition 1
#			format
#			tar
#	(none)	fw_install
#	(reset)	set_reset_flag
#	--partition 2
#			format
#			tar
#	--partition 5
#	(reset)	bk_factory_log
#			format
#			tar
#	(reset)	restore_factory_log
#	--partition 6
#	(reset_full)sanitaize
#			format
#			tar
#	END
#
# .landisk/ --- このディレクトリの中から実行しなければならず、以下のファイルとディレクトリを含んでいることが必要
#    tar2disk, sd1.tgz, sd2.tgz, sd5.tgz, sd6.tgz
#    mnt/ 
# 
# BUG:
#	$SCRIPT_PATH の定義がない。mkfs.xfsとsmartctlがある場所を指していなければならない。
# 	ただし/sbin/mkfs.xfs, /usr/sbin/smartctl があるなら$SCRIPT_PATHが参照されることはない。
# 
# 2017-05-02
# /mnt/hda5/factory_logを初期化直後に作成するようにした。
#


START_TIME=`date`
INTERNAL_HDD="hdb"

EXIT() {
	local code=$1
	echo $2
	echo "STARTED:  $START_TIME"
	echo "END    :  `date`"
	echo --- tar2disk end. code=$code
	exit $code
}


#
# パーティションを切る
#
partition() {
	echo "--- partition(): Clear MBR for $disk"
	dd if=/dev/zero of=/dev/$disk bs=512 count=2 || return 1

	echo "--- partition(): pertitioning for HDL-GS"
	# Windows等に倣い、MBRを含む先頭1MiB(2048セクタ)を空きブロックとしている。
	# 大容量ディスクは4KiB物理セクタなので、512Byte論理セクタで指定する場合8セクタごとの境界にすることが必要。
	# 物理セクタサイズが異なる場合は修正必要。
	# part1 300MiB(614400) tgzイメージとアップデータの保管場所。現状100MiB使用。追加アップデータに備えて+200MiB
	# part2 600MiB(1228800) システム領域。現状実使用200MiB程度。
	# part3 128MiB(262144) swap。実メモリ64MiB*2
	# part4 拡張領域。EPBRが1論理セクタ分確保されてしまうので、次のpart5は+8の位置にすること
	# part5 250MiB(512000) samba等サーバーアプリケーション領域。現状実使用50MiB程度。
	# part6 のこり。ユーザーデータ領域。直前にEPBRが1論理セクタ置かれるので、開始位置はpart5+512000+8とする。
	sfdisk -uS -f /dev/$disk <<EOF || return 3
2048,614400,L
616448,1228800,L
1845248,262144,S
2107392,,E
2107400,512000,L
2619408,,L
EOF
	echo "--- partition(): complete"
	return 0
}

#
# format partition
#
format() {
	local i=$1
	echo "--- format(): formatting $disk$i"
	
	if [ $i -eq 1 ]; then
		if [ $flag_reset -eq 1 ]; then
			echo "--- SKIP format for $disk$i because of command line parameter."
			return 0
		fi
		mke2fs -b 4096 -j -m1 /dev/$disk$i || return 1
	elif [ $i -eq 2 ]; then
		mke2fs -j -m1 /dev/$disk$i || return 1
	elif [ $i -eq 5 ]; then
		mke2fs -j -b 4096 -N 100000 \
			-O dir_index,filetype,sparse_super /dev/$disk$i || return 1
	elif [ $i -eq 6 ]; then
		[ ! -f /sbin/mkfs.xfs ] && cp -a ${SCRIPT_PATH}/mkfs.xfs /sbin/
		mkfs.xfs -f /dev/$disk$i || return 1
	else
		echo "--- SKIP format for $disk$i because of not nessesary"
	fi
	echo "--- format(): complete"
	return 0
}

#
# fw_install
#
fw_install() {
	echo "--- fw_install(): copying .tgz archives, etc.."
	
	touch verify_on_boot
	cp -a ../sd?.tgz ../tar2disk ./.landisk/
	mkdir ./.landisk/mnt
	echo "--- fw_install(): complete"
}


#
# 初期化後updateの為にflag fileをtouchする
#
set_reset_flag() {
	touch ./.landisk/reset_ok
}


#
# 指定ディスクを 0 クリアする
#
sanitize_disk() {
	local i=$1
	echo "--- sanitaize_disk(): zero filling $disk$i"
	dd if=/dev/zero of=/dev/$disk$i bs=4M || return 1
	echo "sanitize_disk(): complete"
}


#
# install_logを 作成する
#
set_install_log() {
	echo "--- recording install log"
	
	local end_time
	local j
	local mac_addr=`/sbin/ifconfig eth0 | sed -n 's/^.*HWaddr \([0-9A-F:]*\)[ ]*$/\1/p'`
	local log_dir="$mnt/factory_log"
	local install_log="$log_dir/install.log"

	mount /dev/${disk}5 $mnt || return 1
	if [ ! -d $log_dir ]; then
		mkdir $log_dir || return 1
	fi
	end_time=`date`
	echo "Mac Address: $mac_addr" > $install_log
	echo "Install Start: $START_TIME" >> $install_log
	echo "Install End: $end_time" >> $install_log
	for j in 1 2 3 4 5 6 7 8 9 10; do
		sync
		umount $mnt && break || sleep 1
	done
}

#
# partition5 にある factorylog を$topdirへ退避
#
bk_factory_log() {
	echo "--- backup factory log"
	
	local factory_tgz=$topdir/factory_log.tar.gz
	if [ ! -f $factory_tgz ]; then
		mount /dev/${disk}5 $mnt || return 1
		tar cpzf $factory_tgz -C $mnt factory_log
		umount $mnt
	fi
}

#
# $topdirにあるfactorylogをカレントディレクトリへ書き戻して、今の作業をログへ追加
#
restore_factory_log() {
	echo "--- restore factory log"
	
	local factory_tgz=$topdir/factory_log.tar.gz
	if [ -f $factory_tgz ]; then
		tar xpzf $factory_tgz
		echo `LANG=C date`: reset_script: >> factory_log/powerlog
		rm -f $factory_tgz
	fi
}


#
# smartチェックを行う
#
smart_check() {
	echo --- smart checking
	
	local RESULT_SMARTCTL=0
	local RESULT_SMARTCTL_BIT0=0
	local RESULT_SMARTCTL_BIT1=0
	local RESULT_SMARTCTL_BIT2=0
	local RESULT_SMARTCTL_BIT3=0

	[ ! -f /usr/sbin/smartctl ] && cp -a ${SCRIPT_PATH}/smartctl /usr/sbin/

	/usr/sbin/smartctl --smart=on --offlineauto=on --saveauto=on /dev/$disk
	/usr/sbin/smartctl -a /dev/$disk
	RESULT_SMARTCTL=$?
	RESULT_SMARTCTL_BIT0=$((${RESULT_SMARTCTL} & 1))
	RESULT_SMARTCTL_BIT1=$((${RESULT_SMARTCTL} & 2))
	RESULT_SMARTCTL_BIT2=$((${RESULT_SMARTCTL} & 4))
	RESULT_SMARTCTL_BIT3=$((${RESULT_SMARTCTL} & 8))

	if [ ${RESULT_SMARTCTL_BIT0} -ne 0 ]; then
	    echo "*** FAILED TO ENABLE S.M.A.R.T. DISK=${disk} ***"
	    echo "*** COMMAND LINE PARSE ERROR ***"
	    return 1
	fi
	if [ ${RESULT_SMARTCTL_BIT1} -ne 0 ]; then
	    echo "*** FAILED TO ENABLE S.M.A.R.T. DISK=${disk} ***"
	    echo "*** DEVICE OPEN FAILED ***"
	    return 1
	fi
	if [ ${RESULT_SMARTCTL_BIT2} -ne 0 ]; then
	    echo "*** FAILED TO ENABLE S.M.A.R.T. DISK=${disk} ***"
	    echo "*** S.M.A.R.T. COMMAND FAILED ***"
	    return 1
	fi
	if [ ${RESULT_SMARTCTL_BIT3} -ne 0 ]; then
	    echo "*** S.M.A.R.T ERROR DETECTED DISK=${disk} ***"
	    echo "*** STATUS: DISK FAILING ***"
	    return 1
	fi
	echo "--- S.M.A.R.T check complete"
	return 0
}


#
# メイン
#
disk=$1
mode=$2
ignoresmart=$3
topdir=`pwd`
mnt=./mnt
PATH=$PATH:/sbin

if [ "x$disk" = "x" ]; then
	echo "usage: tar2disk sda [reset|reset_full|none   [ignore_smart]] 1>&2"
	exit -1
fi

if [ "x$mode" = "xreset" ]; then
	flag_install=0
	flag_reset=1
	flag_reset_full=0
elif [ "x$mode" = "xreset_full" ]; then
	flag_install=0
	flag_reset=1
	flag_reset_full=1
else
	flag_install=1
	flag_reset=0
	flag_reset_full=0
fi


for i in 1 2 5 6; do
	umount /dev/${disk}$i
done

if [ $flag_install -eq 1 ]; then
	smart_check
	if [ $? -ne 0 ] && [ "x$ignoresmart" != "xignore_smart" ]; then
		EXIT 1 "SMART CHECK FAILED."
	else
		echo "--- SMART RESULT IGNORED."
	fi
	partition
fi

mkswap /dev/${disk}3
if [ $disk = $INTERNAL_HDD ]; then
	swapon /dev/${disk}3
	trap "swapoff /dev/${disk}3" 0
fi

for i in 1 2 5 6; do
	cd $topdir
    
	[ $i -eq 6 -a $flag_reset_full -eq 1 ]	&& sanitize_disk $i
	[ $i -eq 5 -a $flag_reset -eq 1 ]	&& bk_factory_log
	format $i || EXIT 1 "FORMAT $disk$i FAILED."
	mount /dev/${disk}$i $mnt || EXIT 1 "MOUNT $disk$i FAILED."

	cd $mnt || EXIT 1 "CD $mnt FAILED."
	echo --- extract tar to $disk$i
	tar zxf ../sd$i.tgz || EXIT 1
	# 2017-05-02 bug fix for factory_log
	[ $i -eq 5 -a ! -d $mnt/factory_log ] 	&& mkdir $mnt/factory_log
	[ $i -eq 1 -a $flag_install -eq 1 ] 	&& fw_install
	[ $i -eq 1 -a $flag_reset -eq 1 ]	&& set_reset_flag
	[ $i -eq 5 -a $flag_reset -eq 1 ]	&& restore_factory_log
	cd $topdir || EXIT 1 "cd $topdir FAILED."
    
	echo --- unmounting
	for j in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20; do
		sync
		umount $mnt && break || sleep 1
	done
	[ "$?" -ne 0 ] && EXIT 1 "umount any FAILED."
done

[ $flag_install -eq 1 ] && set_install_log

EXIT 0 "OK."
 sfdisk -uM を使ってMiB単位での指定がうまく機能すればいいのだが、EPBRのために1MiBの隙間を空けて次のパーティションの開始位置を指定するとsfdiskが「俺はこんな割当気に入らないね!」といって拒否られる。結局、-uS -fでパーティション開始位置を8の倍数セクタに強制することにした。
 あと、/mnt/hda5/factory_logディレクトリがないというバグもここで解決した。

 使い方は、HDL-GSのUSBポートに新品HDDを接続して(/dev/sdaになる)、telnetでHDL-GSの/boot/.landiskに入り、
./tar2disk sda none ignore_smart
とする。USB経由のHDDではSMART情報が採れないことがほとんどなのでignore_smartオプションでこれを無視するようにした。

タグ:

+ タグ編集
  • タグ:

このサイトはreCAPTCHAによって保護されており、Googleの プライバシーポリシー利用規約 が適用されます。

目安箱バナー