2月 142014
自分の知らないところで、あるコマンドが実行されているということはLinuxでは珍しいことではない。代表的なのはcronだ。ただ、cronならcrontab -lをしたり、直接/var/spool/cron/crontabs/*を調べれば、どんなコマンドが実行されるかすぐに調べがつく。しかし、あるイベントが発生したことをトリガーにしてコマンドが実行された場合、なぜそのコマンドが突然呼ばれたのかということに困惑することがある。
例えば、ifupコマンドが実行された場合、/etc/network/if-pre-up.dと/etc/network/if-up.d配下にあるコマンドが、ifupの実行中に呼び出されるようになっている。あるコマンドが実行されていることはログなどからわかっているが、どのような経緯で実行されるに至ったかがわからない、という場合には、そのコマンドの親プロセスを辿っていけば調べることができる。
実行されているコマンドがバイナリだと手も足も出ないかもしれないが、シェルスクリプトであれば、以下のようなスクリプトを使って呼び出し元の親プロセスたちを辿ることができる。
trace_parents()
{
local pid=$$ cmd
while true; do
cmd="$(cat /proc/$pid/cmdline | tr '\0' ' ')"
echo -e "pid=$pid, cmd=$cmd"
[ $pid -eq 1 ] && break
pid=$(awk '/^PPid:/{print $2}' /proc/$pid/status)
done
}
trace_parents > /tmp/parents.$(basename $0).log
PIDが1、すなわちinitになるまで/proc/pid/statusの中から親プロセスのPIDを辿っていくというものだ。/proc/pid/cmdlineをcatでダンプさせると、コマンドライン引数の間にスペースがないように見えるが、区切り文字はnull文字(\0)になっているので、trでスペースに置換すれば見やすくなる。