statの謎

#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>

int main(int argc, char *argv[]) {
  struct stat sb;
  char *file = "/dev/stdin";
  if (stat(file, &sb) == -1) {
    perror("stat");
    exit(EXIT_FAILURE);
  }
  switch (sb.st_mode & S_IFMT) {
    case S_IFBLK: printf("block device\n"); break;
    case S_IFCHR: printf("character device\n"); break;
    case S_IFDIR: printf("directory\n"); break;
    case S_IFIFO: printf("FIFO/pipe\n"); break;
    case S_IFLNK: printf("symlink\n"); break;
    case S_IFREG: printf("regular file\n"); break;
    case S_IFSOCK: printf("socket\n"); break;
    default: printf("unknown?\n"); break;
  }
  exit(EXIT_SUCCESS);
}

/dev/stdinをstatしてみるだけのコード. 実行すると

 $ gcc test.c
 $ ./a.out
character device

これは大丈夫. statはシンボリックリンクを解決するので. ちょっと調べておくと, /dev/stdinは/dev/fd/0へのリンクになってる(環境依存だけど).

 $ file /dev/stdin
/dev/stdin: character special
 $ ls -al /dev/stdin
lr-xr-xr-x  1 root  wheel  0  8 22 14:52 /dev/stdin -> fd/0

ところが...

 $ echo "hoge" | ./a.out
FIFO/pipe
 $ 

うーん, なんでこうなるのかがよう分からんです...

もうちょっと調べてると...

 $ file /dev/fd/0              
/dev/fd/0: character special
 $ echo "hoge" | file /dev/fd/0
/dev/fd/0: fifo (named pipe)

これstatの問題ってよりファイルディスクリプタの問題というか, 何も問題じゃない気がしてきたので, 考えるのやめる. こういうのの仕様ってどこ見ればいいの...