2012年12月4日火曜日

HDL-GS500を、1.0TBに換装して再初期化する。

今まで3回にわたって、HDL-GS500の故障からデータ救出までを書きました。

  1. HDL-GS500が故障。
  2. 壊れたHDDを、Advanced FormatのHDDに交換。
  3. GNU ddrescueを使って、壊れたHDDからデーターを救出。
救出データのバックアップが終わりましたので、今回はHDL-GS500を再初期化しました。
これで1.0TBのHDL-GS500になりました。


再初期化の前にtar2diskを一部修正

データ救出用として暫定修正していたtar2diskを、通常使用できるように修正しました。

  • disk2cyl( )は、データ救出のために500GBに固定していた設定を解除。ディスクのセクター数からモデルを自動識別するように修正。セクターの計算式を見直し、遠回りしていた計算をシンプルにしました。
  • partition( )は、全てのパーティションの開始位置を、アライメント調整した値に修正しました。

修正版tar2disk再初期化用

#!/bin/sh
#
# tar2disk: tar ball をディスクに展開
#
# usage: tar2disk sda
#///// 2012/10/01   sfdiskをシリンダ指定から、セクタ指定へ変更。/////
#///// 2012/11/06   全パーティションのアライメント調整。/////
mnt=./mnt
sddev=/dev/hdb   # ##### 初期化する環境に合わせて変更してください #####

PATH=$PATH:/sbin

#
# 16進->10進変換
#
hex2dec() {
    expr 1 + `printf "%d" $1`
}

#
# モデルごとの制限セクタ数
#
sector160=`hex2dec 0x12A05FBF`
sector250=`hex2dec 0x1D1A9C7F`
sector300=`hex2dec 0x22ECB57F`
sector320=`hex2dec 0x2540BF7F`
sector400=`hex2dec 0x2E90F73F`
sector500=`hex2dec 0x3A353900`
sector750=`hex2dec 0x574FCD9F`
sector1000=`hex2dec 0x74706DAF`

#cyl_end=379        # sda5 の終了セクタ
cyl_end=6088641     #/////シリンダ値をセクタ値に変更/////

#
# ディスク名からモデルで丸められたセクタ数を得る
#///// 2012/10/01   セクタ数を返すように修正 /////
#///// 2012/11/06   修復時の500GB固定を解除、計算式最適化。/////
disk2cyl() {
    local disk=$1
    local sector=`cat /sys/block/$disk/size`
#/////    local sector=976566529    /////
    if [ $sector -lt $sector160 ]; then
        echo -n error
        exit 1
    elif [ $sector -lt $sector250 ]; then
        expr $sector160 - $cyl_end
    elif [ $sector -lt $sector300 ]; then
        expr $sector250 - $cyl_end
    elif [ $sector -lt $sector320 ]; then
        expr $sector300 - $cyl_end
    elif [ $sector -lt $sector400 ]; then
        expr $sector320 - $cyl_end
    elif [ $sector -lt $sector500 ]; then
        expr $sector400 - $cyl_end
    elif [ $sector -lt $sector750 ]; then
        expr $sector500 - $cyl_end
    elif [ $sector -lt $sector1000 ]; then
        expr $sector750 - $cyl_end
    else
        expr $sector1000 - $cyl_end
    fi
    return 0
}

#
# パーティションを切る
#///// 2012/10/01   シリンダ指定からセクタ指定へ変更 sda6の開始セクタは暫定値/////
#///// 2012/11/06   全パーティションのアライメント調整。/////
partition() {
 local disk=$1
 local c5=417687    # 26*255*63-2
 local cyl=`disk2cyl $disk`
 local ext=`expr $cyl + $c5 + 10`

 dd if=/dev/zero of=/dev/$disk bs=512 count=2 || exit 1
 sfdisk -f -uS /dev/$disk <<EOF || exit 1
2048,626536,L
628584,833328,L
1461912,4209032,S
5670944,$ext,E
5670952,$c5,L
6088640,$cyl,L
EOF
}


#
# format
#///// 2012/10/01 ブロックサイズを4096バイトに変更。/////
format() {
 local i=$1

 if [ $i -eq 1 ]; then
  [ $flag_reset -eq 1 ] && return 0
  mke2fs -b 4096 -j -m1 $sddev$i || return 1
 elif [ $i -eq 2 ]; then
  mke2fs -b 4096 -j -m1 $sddev$i || return 1
 elif [ $i -eq 5 ]; then
  mke2fs -b 4096 -j -N 100000 \
   -O dir_index,filetype,sparse_super $sddev$i || return 1
 else
  [ ! -f /sbin/mkfs.xfs ] && cp -a ${SCRIPT_PATH}/mkfs.xfs /sbin/
  mkfs.xfs -f $sddev$i || return 1
 fi
 return 0
}


#
# fw_install
#
fw_install() {
 touch verify_on_boot
 cp -a ../sd?.tgz ../tar2disk ./.landisk/
 mkdir ./.landisk/mnt
}


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


#
# ディスクを 0 クリアする
#
sanitize_disk() {
 local i=$1
 echo "--- sanitize disk"
 dd if=/dev/zero of=$sddev$i bs=1M || return 1
}


#
# install_logを 作成する
#
set_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 ${sddev}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
}

#
# factorylogの退避
#
bk_factory_log() {
 local factory_tgz=$topdir/factory_log.tar.gz
 if [ ! -f $factory_tgz ]; then
  mount ${sddev}5 $mnt || return 1
  tar cpzf $factory_tgz -C $mnt factory_log
  umount $mnt
 fi
}

#
# factorylogの書き戻し
#
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() {
 local disk=$1
 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
 return 0
}


#
# メイン
#
disk=$1
mode=$2
topdir=`pwd`

if [ "$disk" = "" ]; then
 echo usage: tar2disk sda 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 $sddev$i
done

if [ $flag_install -eq 1 ]; then
 smart_check $disk || exit 1
 partition $disk
fi

mkswap /dev/${disk}3
swapon /dev/${disk}3
trap "swapoff /dev/${disk}3" 0

for i in 1 2 5 6; do
 cd $topdir
    
 echo --- partitioning $i
 [ $i -eq 6 -a $flag_reset_full -eq 1 ] && sanitize_disk $i
 [ $i -eq 5 -a $flag_reset -eq 1 ] && bk_factory_log
 echo --- format partition
 format $i || exit 1
 mount $sddev$i $mnt || exit 1

 echo --- extracting tar ball
 cd $mnt || exit 1
 tar zxf ../sd$i.tgz || exit 1
 [ $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
    
 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
done

[ $flag_install -eq 1 ] && set_install_log
exit 0


作業の準備

バックアップが終わったHDL-GS500からHDDを取り出し、USB-SATA変換アダプタ経由でPCに接続しました。このとき間違いを避けるために、元々PCに搭載しているHDDの接続を取り外しておくと、とても安全に作業できます。

  • はじめる前にtar2diskの9行目は、初期化する環境に合わせて変更が必要です。
  • sddev=/dev/hdb   # ##### 初期化する環境に合わせて変更してください #####
    
  • 初期化するHDDのデバイス・ノードは、dmesgなどで確認します。
    例えば、/dev/sdcなら、9行目をsddev=/dev/sdcに変更します。
  • 再セットアップ用ファイルsd1.tgz, sd2.tgz, sd5.tgz, sd6.tgz, tar2diskが入ったUSBメモリ(1回目のときに保存したもの)は、tar2diskの内容を今回の修正版に変更しておきます。

HDDの再初期化

knoppix DVDを起動して端末を立ち上げsu -rootになります。

最初の状態として、

/dev/sdcには、再初期化するHDDが
/dev/sddには、USBメモリが
接続されている状態とします。

USBメモリを、マウントポイントを作成してマウントします。

# mkdir /media/usb
# mount /dev/sdd1 /media/usb

USBメモリのtar2diskを実行します。

# cd /media/usb/hdd1/.landisk
# ./tar2disk sdc
これでHDDが初期化されます。

シリアルコンソールから、sfdiskした結果です。HDDのセクターサイズをtar2diskが自動認識して、計算どおり1.0TBでパーティショニングできました。

# sfdisk -uS -l /dev/hdb

Disk /dev/hdb: 121601 cylinders, 255 heads, 63 sectors/track
Warning: extended partition does not start at a cylinder boundary.
DOS and Linux will interpret the contents differently.
Units = sectors of 512 bytes, counting from 0

   Device Boot    Start       End   #sectors  Id  System
/dev/hdb1          2048    628583     626536  83  Linux
/dev/hdb2        628584   1461911     833328  83  Linux
/dev/hdb3       1461912   5670943    4209032  82  Linux swap / Solaris
/dev/hdb4       5670944 1953525167 1947854224   5  Extended
/dev/hdb5       5670952   6088638     417687  83  Linux
/dev/hdb6       6088640 1953525166 1947436527  83  Linux

再初期化後にHDDに書き込まれたtar2diskは、9行目の修正部分を元のsddev=/dev/hdbに戻しておきます。HDL-GS500の内部から見たHDDのデバイス・ノードは/dev/hdbになっています。

sddev=/dev/hdb   # ##### 初期化する環境に合わせて変更してください #####
この作業を忘れると、Webメニューのシステム初期化を実行する場合に失敗します。

再初期化したHDDでは、第1パーティション(今回の状態ならsdc1)の.landiskディレクトリが、tar2diskの保存場所です。


作業完了

修正後にHDL-GS500を再組立すると作業完了です。

HDL-GS500の、1.0TB化が完了しました。



tar2diskのオプションについて

Webメニューのシステム初期化では、tar2diskに以下のオプションをつけて実行しているようです。

通常の初期化を行う場合

# ./tar2disk hdb reset

内蔵HDDの完全消去を行う場合は

# ./tar2disk hdb reset_full



最後に今回のトラブル談

HDL-GS500のトラブルが解決した後、作業用PCにトラブル発生。

.
.

その日の夜、言いようのない睡魔に襲われながら、再初期化の作業を始めていました。

エラーを出して途中で止まるtar2disk。

「何でやろぅ?おかしいなぁ…」

あまりにも眠たくて、考えようとしても全く頭が働かない。

何度も深い眠りの淵に引き込まれそうになりながら、作業を続けようとしていました。

「もうあかん、今日は無理や…」

とうとう睡魔に勝てず、その夜の作業は諦めて早々に寝ることに。


翌日の夕食後、おもむろに作業を再開。

原因を探るために、前日の作業ログを、以前のログと見比べる。

「何故だかpartitioning 1のinodesの数値が大きい?
Superblock backups stored on blocks:のブロックも多い???」

嫌な予感が…

--- partitioning 1
--- format partition
mke2fs 1.42.2 (9-Apr-2012)
Filesystem label=
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096 (log=2)
Stride=0 blocks, Stripe width=0 blocks
6561792 inodes, 26216064 blocks
262160 blocks (1.00%) reserved for the super user
First data block=0
Maximum filesystem blocks=0
801 block groups
32768 blocks per group, 32768 fragments per group
8192 inodes per group
Superblock backups stored on blocks: 
 32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208, 
 4096000, 7962624, 11239424, 20480000, 23887872

Allocating group tables: done                            
Writing inode tables: done                            
Creating journal (32768 blocks): done
Writing superblocks and filesystem accounting information: done

--- extracting tar ball
--- unmounting
--- partitioning 2
--- format partition
mke2fs 1.42.2 (9-Apr-2012)
mke2fs: Device size reported to be zero.  Invalid partition specified, or
 partition table wasn't reread after running fdisk, due to
 a modified partition being busy and in use.  You may need to reboot
 to re-read your partition table.

tar2diskを見直して、ようやく原因に気づく。

「えぇ~っ、」

「やってしもた~」

諦めの妖精と、執着の妖精たちが、頭の中で踊りだしていました。



少し時間をおいてから、昨晩の様子を思い返すと。

作業PCのHDDを取り外さずに、USB-SATA変換アダプタ経由で、再初期化用のHDDをPCに接続していました。

そして、9行目の修正を忘れて、前の作業のときに設定していたsdaのままで実行。

sddev=/dev/sda   # ##### 初期化する環境に合わせて変更してください #####

つまり、USB-HDDではなく作業用PC のCドライブに書き込んでいたのです。

シェルスクリプトは、指示されたとおりにCドライブをext3でフォーマット後、tarボールを展開していました。その結果、作業PC のCドライブを飛ばしてしまったのでした。

「Windowsが立ち上がらない。困った!」

もう後の祭りです。


ほとんどのファイルは、別ドライブにバックアップを取ったつもりでしたが。マイドキュメントのバックアップが、あまり出来ていなかったことがわかりました。

そのため、データ救出、WindowsXPの再インストール、アプリケーションのインストール、嵐のようなアップデートと再起動の繰り返し等。余計な用事がいっぱい増えてしまい、今まで手間取っていました。

データの救出にはTestDiskPhotoRecを使いました。ほとんどのデジカメ画像が救出できましたが、長年可愛がってきたExcelファイルを幾つか失いました。 残念 X(

「気をつけよう、眠たい時のPC作業」

0 件のコメント :