DTraceでは、集計するだけでなく、データの中身を見ることもできる。
ここでは、特定のファイルへの書き込みが発生した際、該当データを画面に出力するというスクリプトを作ってみよう(リスト3)。
# cat filewrite.d #!/usr/sbin/dtrace -s #pragma D option quiet syscall::open:entry /copyinstr(arg0) == $1/ { self->hook = 1; } syscall::open:return /self->hook == 1/ { self->filedes = arg0; } syscall::write:entry /self->filedes == arg0/ { printf("writedata : %S", stringof(copyin(arg1, arg2))); }
リスト3に示したfilewrite.dで、例えば、/tmp/data.txtを監視したい場合には、次のように指定する。
# dtrace -s filewrite.d "/tmp/data.txt"
この後、別の端末から、/tmp/data.txtに何らかのデータを書き込んでみよう。例えば、viコマンドを使って「/tmp/data.txt」を編集し、保存するとしよう。すると、保存した時に書き込んだ先頭256バイトが、次のように表示されるはずだ(表示される内容は/tmp/data.txtに書き込んだデータによって異なる)。
# dtrace -s filewrite.d "/tmp/data.txt"
writedata : abcdef\ngh\nijk\nlmn\n\0
ファイルへの書き込みが発生する場合には、writeシステムコールが呼び出される。しかし、writeシステムコールが呼び出された段階では、ファイル名が分からない。ファイル名が判明するのは、ファイルを開く場合に呼び出されるopenシステムコールが発生した時だ。
そこでリスト3では、まず、openシステムコールのentryプローブとreturnプローブをフック処理をしている。「man -s2 open」としてopenシステムコールのmanを見ると分かるが、openシステムコールは、第1引数に「ファイル名」が渡される。そして、戻り値としてファイルを読み書きするためのファイルディスクリプタが返されるのだ。リスト3では、次のようにして、第1引数が「$1」に合致するものをプローブ処理している。
syscall::open:entry /copyinstr(arg0) == $1/ { self->hook = 1; }
copyinstrは、データを文字列化するサブルーチンだ(Solaris Dynamic Tracing Guideの「Chapter 33 User Process Tracing」を参照)。
そして、$1はdtraceに渡した第1番目の引数を示す。つまり、「dtrace -s filewrite.d "/tmp/data.txt"」として実行した場合、「$1」は「"/tmp/data.txt"」を意味する。ここでは、引数に指定したファイルが開かれた場合に「self->hookに1を代入する」という処理をしているのだ。
そして、openシステムコールのreturnプローブでは、arg0の値をself->filedes変数に格納している。
syscall::open:return /self->hook == 1/ { self->filedes = arg0; }
arg0は、openシステムコールからの戻り値である。openシステムコールからの戻り値は、ファイルディスクリプタを返すので、これにより、self->filedes変数には、ファイルディスクリプタが保存される。
ここでは条件として、「/self->hook == 1/」を指定している。self->hookは、先にentryプローブで調べたいファイルが引数として渡されたときに「1」に設定している。すなわち、この条件は、「entryプローブで該当するファイル名が渡されたときだけ実行」という意味になる。
さて肝心のwriteシステムコールの処理では、次のように、「self->filedes == arg0」という条件を指定している。
Copyright © ITmedia, Inc. All Rights Reserved.