アプリのログを/dev/null
に流してしまった。すでに流れてしまったものは取り戻せないが、以降のログをなんとかプロセスを生かしたままファイルに出力させたいという場合はよくある。
gdb
を使えばそれが可能となる。
追記:
書いた後ですでに同じような記事があるのを見つけてしまったが若干やり方が異なっていたりしたのでそのまま公開。
準備
1秒毎にHelloを出力するだけのプログラム。
hello.cpp
#include <iostream>
#include <unistd.h>
int main(int argc, char *argv[])
{
while(true) {
std::cout << "Hello" << std::endl;
sleep(1);
}
return 0;
}
$ g++ -o hello hello.cpp
$ ./hello
Hello
Hello
...
gdbで出力先変更
標準出力を/dev/null
にリダイレクトしてみる
$ ./hello > /dev/null
プロセスが持つファイルディスクリプタ一覧の/proc/$(pidof hello)/fd
を見ると確かに標準出力(1)が/dev/null
に向かっていることがわかる
$ ls -la /proc/$(pidof hello)/fd
合計 0
dr-x------ 2 maueki maueki 0 10月 2 15:26 .
dr-xr-xr-x 9 maueki maueki 0 10月 2 15:26 ..
lrwx------ 1 maueki maueki 64 10月 2 15:26 0 -> /dev/pts/4
l-wx------ 1 maueki maueki 64 10月 2 15:26 1 -> /dev/null
l-wx------ 1 maueki maueki 64 10月 2 15:26 2 -> /dev/pts/4
gdbを使って標準出力を/tmp/hello_log
に流れるようにしてみる。
$ gdb
...
(gdb) shell pidof hello
25168
(gdb) attach 25168
Attaching to process 25168
...
(gdb) call open("/tmp/hello_log", 66, 0666)
$1 = 3
(gdb) call dup2($1, 1)
$2 = 1
(gdb) call close($1)
$3 = 0
(gdb) detach
Detaching from program: /tmp/hello, process 25168
(gdb) quit
これで出力先が変更された
$ cat /tmp/hello_log
Hello
Hello
...
/proc/$(pidof hello)/fd
を見ても確かに変更されている
$ ls -la /proc/$(pidof hello)/fd
合計 0
dr-x------ 2 maueki maueki 0 10月 2 15:26 .
dr-xr-xr-x 9 maueki maueki 0 10月 2 15:26 ..
lrwx------ 1 maueki maueki 64 10月 2 15:26 0 -> /dev/pts/4
l-wx------ 1 maueki maueki 64 10月 2 15:26 1 -> /tmp/hello_log
l-wx------ 1 maueki maueki 64 10月 2 15:26 2 -> /dev/pts/4
解説
gdbのcall
コマンドではCの関数が呼び出せる。
- まずopenで差し替え先ファイルを開く。引数の66は
O_CREAT|O_RDWR
。ファイルディスクリプタが$1
に入る - 次にdup2で
$1
を標準出力(1)として複製する - 最後に
$1
をcloseして終わり
おわりに
今回は標準出力を差し替えたが基本的にどのファイルでも差し替えが可能。以下のサイトではプロセスが開いている任意のファイルを差し替えるスクリプトが公開されている。