/proc/$PID/fd とテンポラリファイル

http://memo.officebrook.net/20110211.html を見て,なるほどそうやってファイルを取り出せるのかと感心した.


UNIX では open(2) で既に開かれているファイルを unlink(2) してもファイルディスクリプタは有効であり続け,実際に消えるのは close(2) されたときになる.
このことを利用して open(2) した直後に unlink(2) することで,tmpfile(3) のようにプロセスが終了したときに勝手に消えるテンポラリファイルを作ることができる.


で,この unlink(2) されたけどファイルディスクリプタは生きているようなファイルはディレクトリからは見えないけど,/proc/$PID/fd でどうやら参照できるために↑のような形で取り出せるようだ.
この様子を確認するためにこんなコードを書いて実行してみた.

#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>

int main(void)
{
  const char path[] = "/tmp/hello.txt";

  int fd = open(path, O_WRONLY | O_CREAT | O_EXCL, 0600);
  system("ls -l /proc/self/fd");
  system("ls -l /tmp/hello.txt");
  unlink(path);
  system("ls -l /proc/self/fd");
  system("ls -l /tmp/hello.txt");
  write(fd, "hello\n", 6);
  system("cat /proc/self/fd/3");
  close(fd);
  system("ls -l /proc/self/fd");
  return 0;
}

実行結果.0 が /dev/null になってたり 1,2 がファイルになっているのは quickrun で実行したから.

合計 0
lrwx------ 1 eagletmt eagletmt 64  2月 12 01:11 0 -> /dev/null
l-wx------ 1 eagletmt eagletmt 64  2月 12 01:11 1 -> /tmp/v9d5oqW/5
l-wx------ 1 eagletmt eagletmt 64  2月 12 01:11 2 -> /tmp/v9d5oqW/5
l-wx------ 1 eagletmt eagletmt 64  2月 12 01:11 3 -> /tmp/hello.txt
lr-x------ 1 eagletmt eagletmt 64  2月 12 01:11 4 -> /proc/18885/fd
-rw------- 1 eagletmt eagletmt 0  2月 12 01:11 /tmp/hello.txt
合計 0
lrwx------ 1 eagletmt eagletmt 64  2月 12 01:11 0 -> /dev/null
l-wx------ 1 eagletmt eagletmt 64  2月 12 01:11 1 -> /tmp/v9d5oqW/5
l-wx------ 1 eagletmt eagletmt 64  2月 12 01:11 2 -> /tmp/v9d5oqW/5
l-wx------ 1 eagletmt eagletmt 64  2月 12 01:11 3 -> /tmp/hello.txt (deleted)
lr-x------ 1 eagletmt eagletmt 64  2月 12 01:11 4 -> /proc/18887/fd
ls: /tmp/hello.txt にアクセスできません: そのようなファイルやディレクトリはありません
hello
合計 0
lrwx------ 1 eagletmt eagletmt 64  2月 12 01:11 0 -> /dev/null
l-wx------ 1 eagletmt eagletmt 64  2月 12 01:11 1 -> /tmp/v9d5oqW/5
l-wx------ 1 eagletmt eagletmt 64  2月 12 01:11 2 -> /tmp/v9d5oqW/5
lr-x------ 1 eagletmt eagletmt 64  2月 12 01:11 3 -> /proc/18889/fd