web-dev-qa-db-ja.com

プログラムがアクセスするファイルを一覧表示する

timeは、特定のコマンドがどれだけのCPU時間を消費するかを知りたい場合に最適なコマンドです。

プログラムとその子によってアクセスされているファイルを一覧表示できる同様のものを探しています。リアルタイムで、または後でレポートとして。

現在私は使用しています:

#!/bin/bash

strace -ff -e trace=file "$@" 2>&1 | Perl -ne 's/^[^"]+"(([^\\"]|\\[\\"nt])*)".*/$1/ && print'

ただし、実行するコマンドにSudoが含まれている場合は失敗します。あまりインテリジェントではありません(存在するファイルまたはアクセス許可の問題があるファイルのみを一覧表示できるか、それらを読み取るファイルと書き込むファイルにグループ化できればいいでしょう)。また、straceは遅いため、より高速な選択で十分です。

65
Ole Tange

私は自分のツールをあきらめてコーディングしました。そのドキュメントから引用するには:

SYNOPSIS
    tracefile [-adefnu] command
    tracefile [-adefnu] -p pid

OPTIONS
    -a        List all files
    -d        List only dirs
    -e        List only existing files
    -f        List only files
    -n        List only non-existing files
    -p pid    Trace process id
    -u        List only files once

ファイルを出力するだけなので、straceからの出力を処理する必要はありません。

https://gitlab.com/ole.tange/tangetools/tree/master/tracefile

56
Ole Tange

straceを使用してシステムコールを追跡できますが、実際には速度の低下が避けられません。管理者特権でコマンドを実行する場合は、straceをrootとして実行する必要があります。

Sudo strace -f -o foo.trace su user -c 'mycommand'

より速くなる可能性が高いもう1つの方法は、ファイルシステムアクセス関数をラップするライブラリLD_PRELOAD=/path/to/libmywrapper.so mycommandをプリロードすることです。 LD_PRELOAD環境変数は、昇格された特権で呼び出されたプログラムには渡されません。そのラッパーライブラリのコードを記述する必要があります( 「楽しみと利益のためにライブラリインターポーザーを構築する」の例です) ); Web上で利用可能な再利用可能なコードがあるかどうかはわかりません。

特定のディレクトリ階層内のファイルを監視している場合は、 LoggedFS を使用してファイルシステムのビューを作成し、そのビューを介したすべてのアクセスがログに記録されるようにすることができます。

loggedfs -c my-loggedfs.xml /logged-view
mycommand /logged-view/somedir

LoggedFSを構成するには、プログラムに同梱されているサンプル構成から始めて、 LoggedFS構成ファイルの構文 をお読みください。

別の可能性は、Linuxの 監査サブシステム です。 auditdデーモンが開始されていることを確認してから、ログに記録する内容を auditctl で構成します。ログに記録された各操作は、/var/log/audit/audit.logに記録されます(通常のディストリビューション)。特定のファイルの監視を開始するには:

auditctl -a exit,always -w /path/to/file

監視をディレクトリに置くと、その中のファイルとそのサブディレクトリも再帰的に監視されます。監査ログを含むディレクトリを監視しないように注意してください。ロギングを特定のプロセスに制限できます。使用可能なフィルターについては、auditctlのマニュアルページを参照してください。監査システムを使用するには、rootである必要があります。

私はあなたがlsof(おそらくプログラムのgrepとその子にパイプされている)が欲しいと思います。ファイルシステムで現在アクセスされているすべてのファイルを教えてくれます。プロセスがアクセスしたファイルに関する情報について( ここから ):

lsof -n -p `pidof your_app`
7
unclejamil

tracefileを試しました。私にとっては、自分の_strace ... | sed ... | sort -u_よりも一致がはるかに少なかった。 _-s256_をstrace(1)コマンドラインに追加しましたが、あまり役に立ちませんでした...

それからloggedfsを試しました。最初に、ログに記録しようとしたディレクトリへの読み取り/書き込みアクセス権がないため、失敗しました。 chmod 755を実行した後、一時的にヒットしました...

しかし、私にとっては、次のことを行うのが最も効果的であると思われます。

_inotifywait -m -r -e OPEN /path/to/traced/directory_

そして、目的のプロセスを実行した後、出力を後処理します。

これはトレースされたディレクトリ以外のファイルプロセスアクセスをキャッチしません。また、他のプロセスが同じディレクトリツリーにアクセスしたかどうかもわかりませんが、多くの場合、これはジョブを取得するのに十分なツールです完了しました。

編集:inotifywaitはシンボリックリンクのアクセスをキャッチしません(シンボリックリンクが解決された後のターゲットのみ)。プログラムがアクセスするライブラリを将来使用するためにアーカイブしたとき、私はこれに見舞われました。いくつかの特別なPerl globハッカーを使用して、通知されたライブラリーに沿ってシンボリックリンクを選択し、その特定のケースで作業を完了させました。

EDIT2:少なくともinotifywaitコマンドライン(たとえば、_inotifywait -m file symlink_または_inotifywait symlink file_)の出力からファイルとシンボリックリンクをinotifyする場合、コマンドラインの最初にあるファイルへのアクセスが表示されます(どちらに関係なく、filesymlinkにアクセスします)。 inotifywaitはIN_DONT_FOLLOWをサポートしていません-プログラムで試したところ、コマンドラインでの順序に関係なく、fileへのアクセスが表示されるだけです(期待どおりかどうかはわかりません)。

2
Tomi Ollila

それはあなたに十分な制御を与えないかもしれませんが(まだ?)私は少なくとも部分的にあなたのニーズを満たすプログラムを書きました、linux-kernelのfanotifyとunshareを使用して特定のプロセスとその子によって変更された(または読み込まれた)ファイルのみを監視します。 straceと比較すると、かなり高速です(;

https://github.com/tycho-kirchner/shournal にあります

シェルの例:

$ shournal -e sh -c 'echo hi > foo1; echo hi2 > foo2'
$ shournal -q --history 1
  # ...
  Written file(s):                                                                                                                                                                              
 /tmp/foo1 (3 bytes) Hash: 15349503233279147316                                                                                                                                             
 /tmp/foo2 (4 bytes) Hash: 2770363686119514911    
1
spawn