ファイルシステム
次のような感じでdtrace(8)コマンドを実行すると、コマンドがどのファイルを開いたかを調べられるといったことは以前説明しました。コマンドやデーモンが使っている設定ファイル、使っているデータ、書き込んでいるファイル、影響を与えているファイルなんかを調べたいときにこの方法を使うと便利です。
図 open(2)システムコールをトレース
# dtrace -n 'syscall::open:entry{printf("%s %s",execname,copyinstr(arg0))}'
dtrace: description 'syscall::open:entry' matched 2 probes
CPU ID FUNCTION:NAME
1 64044 open:entry pkg /etc/pkg/
1 64044 open:entry pkg /usr/local/etc/pkg/repos/
1 64044 open:entry pkg /tmp/meta.txz.WJDegY
1 64044 open:entry pkg /etc/resolv.conf
2 64044 open:entry pkg /etc/nsswitch.conf
2 64044 open:entry pkg /etc/hosts
2 64044 open:entry pkg /etc/services
2 64044 open:entry pkg /usr/share/zoneinfo/UTC
2 64044 open:entry pkg /usr/share/zoneinfo/posixrules
2 64044 open:entry pkg /etc/localtime
2 64044 open:entry pkg /usr/share/zoneinfo/posixrules
2 64044 open:entry pkg /tmp/packagesite.yaml.txz.z61Zy6
2 64044 open:entry pkg /etc/hosts
2 64044 open:entry pkg /etc/services
3 64044 open:entry cron /etc/spwd.db
3 64044 open:entry cron /etc/login.conf.db
3 64044 open:entry cron /etc/group
3 64044 open:entry cron /root/.login_conf.db
3 64044 open:entry cron /root/.login_conf
3 64044 open:entry cron /etc/login.conf.db
0 64044 open:entry cron /etc/spwd.db
0 64044 open:entry cron /etc/login.conf.db
0 64044 open:entry cron /etc/group
0 64044 open:entry cron /root/.login_conf.db
0 64044 open:entry cron /root/.login_conf
0 64044 open:entry cron /etc/login.conf.db
0 64044 open:entry sh /etc/libmap.conf
0 64044 open:entry sh /var/run/ld-elf.so.hints
0 64044 open:entry sh /lib/libedit.so.7
0 64044 open:entry sh /lib/libncurses.so.8
0 64044 open:entry sh /lib/libc.so.7
3 64044 open:entry atrun .
0 64044 open:entry atrun /etc/libmap.conf
0 64044 open:entry atrun /var/run/ld-elf.so.hints
0 64044 open:entry atrun /usr/lib/libpam.so.5
0 64044 open:entry atrun /lib/libutil.so.9
0 64044 open:entry atrun /lib/libc.so.7
0 64044 open:entry atrun .
上記サンプルですと、4列目がコマンド名、5列目がオープンしたファイルのリストになっています。このコマンドを実行してから調べたいコマンドやデーモンを実行すると、どんなファイルが使われているのかを調べることができます。
dtrace(8)を使うと、ほかのプローブを指定してそうした情報を得ることもできます。次のDスクリプトを実行するとvfs::vop_create:entryとvfs::vop_remove:entryをモニタリングしてどのファイルが作成されたとか、削除されたとかを調べることができます。
リスト ほかのプローブを指定してもうちょっと細かくみてみる(vfslite.d)
#!/usr/sbin/dtrace -s
#pragma D option quiet
#pragma D option switchrate=10hz
dtrace:::BEGIN
{
printf("%-12s %6s %6s %-12.12s %-12s %s\n", "TIME(ms)",
"UID", "PID", "PROCESS", "CALL", "DIR/FILE");
}
vfs::vop_create:entry,
vfs::vop_remove:entry
{
this->dir = args[0]->v_cache_dd != NULL ?
stringof(args[0]->v_cache_dd->nc_name) : "<null>";
this->name = args[1]->a_cnp->cn_nameptr != NULL ?
stringof(args[1]->a_cnp->cn_nameptr) : "<null>";
printf("%-12d %6d %6d %-12.12s %-12s %s/%s\n",
timestamp / 1000000, uid, pid, execname, probefunc,
this->dir, this->name);
}
実行するとこんな感じになります。vop_*のところでモニタリングしてデータを得ていることがわかります。中身がわかっていないとそもそもこういった使い方はできませんけれども、こういったことができるということは知っておいて損はないと思います。
図 実行結果
# ./vfslite.d
TIME(ms) UID PID PROCESS CALL DIR/FILE
2201282829 0 53958 pkg vop_create tmp/meta.txz.Oobq5r
2201282829 0 53958 pkg vop_remove tmp/meta.txz.Oobq5r
2201283089 0 53958 pkg vop_create tmp/packagesite.yaml.txz.LtYHfS
2201283089 0 53958 pkg vop_remove tmp/packagesite.yaml.txz.LtYHfS
2201284582 0 53960 pkg vop_create tmp/meta.txz.ImITVo
2201284582 0 53960 pkg vop_remove tmp/meta.txz.ImITVo
2201284820 0 53960 pkg vop_create tmp/packagesite.yaml.txz.Fmr1Cn
2201284820 0 53960 pkg vop_remove tmp/packagesite.yaml.txz.Fmr1Cn
2201285058 0 53960 pkg vop_create pkg/local.sqlite-journal
2201285060 0 53960 pkg vop_remove pkg/local.sqlite-journal
2201285060 0 53960 pkg vop_create pkg/local.sqlite-journal
2201285061 0 53960 pkg vop_remove pkg/local.sqlite-journal
2201285097 0 53960 pkg vop_create pkg/local.sqlite-journal
2201285098 0 53960 pkg vop_remove pkg/local.sqlite-journal
2201285098 0 53960 pkg vop_create pkg/local.sqlite-journal
2201285099 0 53960 pkg vop_remove pkg/local.sqlite-journal
簡単なコマンドですが、次のようにchdir(2)システムコールでデータを取得すると、いわゆるcdコマンドでディレクトリを移動したときをフックして移動先のディレクトリの一覧を得ていくことができます。このコマンドであればcdコマンドでカレントディレクトリを変更するごとにトレース結果が出力されるので、動作がわかりやすいと思います。
図 cdコマンド(chdir(2)システムコール)のディレクトリを追っていく
# dtrace -n 'syscall::chdir:entry{printf("%s",copyinstr(arg0))}'
dtrace: description 'syscall::chdir:entry' matched 2 probes
CPU ID FUNCTION:NAME
3 64058 chdir:entry /root
3 64058 chdir:entry /usr/local
3 64058 chdir:entry /usr/local/share
2 64058 chdir:entry /usr/share
2 64058 chdir:entry /usr/share/doc
3 64058 chdir:entry /usr/share/doc/llvm
0 64058 chdir:entry /usr/share/doc/llvm/clang
0 64058 chdir:entry /etc
0 64058 chdir:entry /usr/local/etc
0 64058 chdir:entry /usr/local/etc/rc.d
0 64058 chdir:entry /root
1 64058 chdir:entry /home
1 64058 chdir:entry /home/suzuki
情報を表示する*stat系のコマンドだと決まった情報しか取得できませんが、dtrace(8)を使うと欲しい情報を欲しい形に加工して得ることができますので、使えるようになればなるほど便利です。書籍『DTrace Dynamic Tracing In Oracle Solaris, Mac OS X & FreeBSD』にはいろんなサンプルと説明が載っていますので(そのままだと実行できないサンプルも多いのですが) 、説明を読みながらいろいろ試してもらえればと思います。
勉強会
第60回 2月23日(木)19:00~FreeBSD勉強会
発表内容検討中。発表ネタをお持ちの方、ぜひご連絡ください。
参加申請はこちら から。
第61回 3月23日(木)19:00~FreeBSD勉強会:リキャップ・ザ・AsiaBSDCon 2017 ~日本語でふりかえるABC~
2017年3月9~12日まで東京でAsiaBSDCon 2017 が開催される予定です。ぜひこのカンファレンスにご参加いただきたいわけなのですが、なかにはどうしても仕事の都合で参加できなかったとか、正直英語がよくわからなかったとか、そういった方もいらっしゃるのではないかと思います。
3月のFreeBSD勉強会では、AsiaBSDCon 2017のあとというこのタイミングを活かして、AsiaBSDCon 2017の発表内容を振り返ってみよう、というのをやってみようと思います。AsiaBSDConに参加しているにもかかわらず、これまで一度もプロシーディングを読み返したことすらないというあなた、ぜひプロシーディングを持参してご参加ください :) AsiaBSDConに参加できなかったというあなたも、この機会をお見逃しなく(できればAsiaBSDConそのものに参加した方が絶対的によいです、あしからず) 。
FreeBSD勉強会 発表者募集
FreeBSD勉強会では発表者を募集しています。FreeBSDに関して発表を行いたい場合、@daichigoto までメッセージをお願いします。1時間半~2時間ほどの発表資料を作成していただき発表をお願いできればと思います。