web-dev-qa-db-ja.com

debugfsを使用してddrescueマップファイルをバッチ処理する

mapfileによって生成されたddrescueがあり、各行が次のようになっている418個の不良セクターがリストされています(マイナスは不良ブロックを示します)。

Position      Size
0x1CC7C68000  0x00001000  -

バイト単位の位置をパーティションの相対セクター番号に変換することで、debugfsを使用してiノード番号を照会し、壊れたファイルのパスを見つけることができます。これを手動で行うことは、ほぼ2000の不良ブロックでは実行できないため、これを自動化したいと思います。ファイルシステムで一連のコマンドを実行するためにdebugfsをスクリプト化する方法はありますか?

壊れたセクターのファイル名を取得するために現在行っていることは次のとおりです。

  1. ddrescuemapfileの位置は、ディスクの先頭を基準にしたバイト単位です。最初に、512で除算して位置をセクター番号に変換し、次にパーティションの開始セクター位置を減算します。

    最初のセクターのパーティション:91914240不良ブロック位置:0x1CC7C68000 10進数:123610759168絶対セクター位置:123610759168/512 = 241427264パーティション上の相対ブロック位置:241427264-91914240 = 149513024

したがって、不良セクタは、パーティションの開始に対して149513024にあり、debugfsを使用して、iノードを見つけることができます。

$ debugfs
debugfs: open /dev/sdd3
debugfs: icheck 149513024
Block       Inode number
149513024   1183169
debugfs: ncheck 1183169
Inode   Pathname
1183169 /username/foo/bar/baz

このプロセスを自動化して、ブロック位置のリストをdebugfsに渡し、これらのブロックをiノードに解決し、iノードをフィルタリングしてマップされていないiノードを除外してから、ncheckを使用してパスを解決できるようにします。残りのiノードの名前。これはdebugfsといくつかのシェルスクリプトで可能ですか?

1
lanoxx

私のrpi3b + SDカードが死んだ後、私は今日これをしなければなりませんでした。ファイルパスを自動的に吐き出すことを除いて、上記のbashスクリプトで行ったことを実行するpythonスクリプトを作成することになりました。ここで確認できます: https:/ /github.com/zkrx/rescue2path

このソリューションでは、まだスクレイピングされていないデータのチャンク( '/')もチェックします。ここではスクレイピングに非常に長い時間がかかり、完了する前に停止しました。

Arch wikiのこのエントリは特に役に立ちました: https://wiki.archlinux.org/index.php/Identify_damaged_files

1
zkrx

私は自分の問題の解決策を見つけたと信じています。しかし、誰かがもっとエレガントな解決策を思いついたり、私の解決策に間違いを見つけたりできるかどうか、私はまだ興味があります。

結局のところ、debugfsのstdinに書き込むことができたので、debugfsの出力を分析するために、ddrescueの一連のコマンドを生成するだけで済みました。

次のbashスクリプトは、ddrescueによって作成された現在のディレクトリに_mapfile.ddrescue_という名前のファイルが存在することを前提としています。

_for line in \
    $(cat mapfile.ddrescue | \
      grep -e "-$" | \
      awk -F" " '{print $1}' | \
      awk -F"0x" '{print $2}'); \
do \
    position=$(( 16#$line / 512 - 91914240 )); \
    result="$result $position"; \
done; \
echo -e "open /dev/sdd3\nicheck $result\nquit\n" | Sudo debugfs
_

このスクリプトの機能は次のとおりです。

  1. mapfileからddrescueを解析します。これを_mapfile.ddrescue_と名付けました。
  2. ハイフンで終わる行のみを保持するようにフィルタリングします。それらは不良ブロックのあるポジションです。
  3. Awkを使用して空白で分割し、位置である最初のトークンを出力します。これには、0x34A933F000などの16進数が含まれます。
  4. Oxプレフィックスを削除します。
  5. 結果は$(...)によって返されます。呼び出し手は、forループへの入力として機能するため、行には常に1つの位置が含まれます。
  6. $(( ... ))式を使用して、位置の計算を行い、位置を512で除算し(たとえば、セクターあたりのバイト数)、パーティションの開始を減算します。私の場合は_91914240_です。これにより、パーティションの開始を基準にしたセクター内の位置がわかります。
  7. 各位置を、_$result_に格納されているスペースで区切られたリストに連結します。
  8. 最後に、Sudoで実行するdebugfsコマンドのstdinにパイプする改行区切りのコマンドリストを生成します。このコマンドはデバイスを開きます(私の場合は_/dev/sdd3_)。次に、_$result_でicheckを実行し、debugfsを終了します。

このスクリプトを実行したとき、debugfsはそれらのブロックのすべてのinodesを見つけるのに長い時間がかかりました。私の場合、出力が出力されるまで数分間ハングしたように見えました。

スクリプトが完了したら、結果をテキストファイルにコピーして分析しました。幸いなことに、ほとんどのセクターは未割り当てのブロックを指しており、残りのセクターは同じ少数のinode番号を指しています。 _<block not found>_で行を削除し、重複を削除した後、残ったinodesは4つだけで、debugfsを使用してncheckで手動で確認できました。これにより、4つのファイルパスが得られました。これらは、バックアップから復元しようとするファイルです。

背景私はもともとddから始め、256GBSSDの内容をより大きなSSDにコピーしたいと考えていました。 ddは最後のパーティションの約45/185GBでI/Oエラーで中止されました。ただし、ddrescueを使用すると、ドライブの99.99%を節約できます。最後に、上記の解決策で、残りの1700kbまたは418の不良領域がどのファイルに属しているかを確認し、壊れているファイルは4つだけでした。これにより、どのファイルが壊れているかがわかり、古いバックアップからそれらを復元できるため、復元されたデータに対する信頼が十分に高まりました。

0
lanoxx