web-dev-qa-db-ja.com

Apacheによって開かれたままになっている削除されたファイルを回復しますか?

Apacheログファイルが削除されたが、Apacheによって開かれたままになっているとします。それからこれは私がしていることです:

pid=$(lsof | grep text.txt | awk '/deleted/ {print $2}')
fd=$(lsof | grep text.txt | awk '/deleted/ {print $4}' | grep -oE "[[:digit:]]{1,}")

cp /proc/$pid/fd/$fd directorytobecopied/testfile.txt

これは、ファイルを回復して元の場所に戻すために私が行っていることです。上記のコードは見栄えが悪いので、これを行う簡単な方法はありますか?さらに、ファイルがどこから削除されたか(directorytobecopied)をどのように知ることができるので、ファイルが元の場所にあるかを誰かに手動で尋ねて、そこに戻す必要がありません。

10
munish

ファイルが削除されたがまだ開いている場合、そのファイルはファイルシステムにまだ存在します( inode があります) ハードリンク カウントは0です。ファイルへのリンクがないため、名前で開くことはできません。 iノードでファイルを開く機能もありません。

ファイルシステムを介してファイルを検出する方法はありません。特に、最後にあったディレクトリでファイルを検索する方法はありません。ディレクトリエントリがなくなりました。残っているのはファイル自体だけです。ファイルシステムデバッガーを使用してファイルにアクセスできますが、これにはroot権限が必要であり、使用が難しく、エラーが発生しやすくなります。

Linuxは、_/proc_の下の特別なシンボリックリンクを介して開いているファイルを公開します。これらのリンクは_/proc/12345/fd/42_と呼ばれます。ここで、12345はプロセスのPIDで、42はそのプロセスの ファイル記述子 の番号です。そのプロセスと同じユーザーとして実行されているプログラムは、ファイルにアクセスできます(読み取り/書き込み/実行のアクセス許可は、ファイルが削除されたときと同じです)。

ファイルが開かれた名前は、シンボリックリンクのターゲットに引き続き表示されます。ファイルが_/var/log/Apache/foo.log_の場合、リンクのターゲットは/var/log/Apache/foo.log (deleted)です。 (ファイルが開かれた後に名前が変更された場合、シンボリックリンクのターゲットは名前の変更を反映する場合があります。)

したがって、次のように、開いているプロセスのPIDと開いている記述子を指定すると、開いている削除済みファイルの内容を回復できます。

_recover_open_deleted_file () {
  old_name=$(readlink "$1")
  case "$old_name" in
    *' (deleted)')
      old_name=${old_name%' (deleted)'}
      if [ -e "$old_name" ]; then
        new_name=$(TMPDIR=${old_name%/*} mktemp)
        echo "$oldname has been replaced, recovering content to $new_name"
      else
        new_name="$old_name"
      fi
      cat <"$1" >"$new_name";;
    *) echo "File is not deleted, doing nothing";;
  esac
}
recover_open_deleted_file "/proc/$pid/fd/$fd"
_

プロセスIDのみがわかっていて、記述子がわからない場合は、次のコマンドを使用してすべてのファイルを回復できます。

_for x in /proc/$pid/fd/*; do
  recover_open_deleted_file "$x"
done
_

プロセスIDもわからない場合は、すべてのプロセスを検索できます。

_for x in /proc/[1-9]*/fd/*; do
  case $(readlink "$x") in
    /var/log/Apache/*) recover_open_deleted_file "$x";;
  esac
done
_

lsofの出力を解析してこのリストを取得することもできますが、単純でも信頼性も移植性も高くありません(これはとにかくLinux固有です)。