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