A process gets three file descriptors from the shell, 0 is stdin, 1 is stdout, 2 is stderr. Normally, these are connected to the process's controlling terminal, but any of these three could be redirected by the shell to some other device or file, including a tty which is not the process's controlling terminal (ctty).

Ok, so how can a process tell if one of 0, 1, 2 is actually connected to its ctty?

Here is what I tried, but it doesn't work:

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/sysmacros.h>

void dump(int fd)
{
  if (isatty(fd))
    {
      struct stat statbuf;
      fstat(fd, &statbuf);
       printf("%d is a tty called %s device ID %d %d \n",
             fd,
             ttyname(fd),
             major(statbuf.st_rdev),
             minor(statbuf.st_rdev));
    };
}

int main ()
{
  dump(0);
  dump(1);
  dump(2);
  dump(open("/dev/tty", O_RDWR));
}

Here is the output:

$ ./a.out
0 is a tty called /dev/pts/1 device ID 136 1
1 is a tty called /dev/pts/1 device ID 136 1
2 is a tty called /dev/pts/1 device ID 136 1
3 is a tty called /dev/tty device ID 5 0

By definition, /dev/tty is the ctty, and obviously 0, 1, and 2 are also connected to the controlling terminal, because I didn't redirect them but the process doesn't know that, and they don't match by name or by device ID, so how can the process be sure that they are connected to its ctty?

$ ./a.out  </dev/null 2>/dev/null
1 is a tty called /dev/pts/1 device ID 136 1
3 is a tty called /dev/tty device ID 5 0

Ok, now stdin and stdout aren't ttys at all, as expeced.

Also, check this out:

$ ./a.out </dev/tty
0 is a tty called /dev/tty device ID 5 0
1 is a tty called /dev/pts/1 device ID 136 1
2 is a tty called /dev/pts/1 device ID 136 1
3 is a tty called /dev/tty device ID 5 0

...when I explicitly redirect /dev/tty to stdin, it does match.

So how does a process know if the stdio fds are connected to its controlling terminal? Am I forgetting something obvious?

--
Anthony Carrico

Reply via email to