Reputation: 2615
close(fileno(stdout));
int fd = dup(fileno(stdin));
//printf("Hello World\n");
write(fd, "Hello", 7);
Here for both printf and write is writing Hello to the screen..But I think they should not because I am duplicating the stdin
to 1 or stdout
closed perviously. And printf
is connected to stdout
but not stdin
but still they are printing...Please explain if I have anything wrong in understanding the dup
Upvotes: 2
Views: 506
Reputation: 10261
The printf
and write
in your code happen to work, due to historical custom. Here's what's happening:
When a user logs into a terminal on a Unix-like system, or opens a terminal window under X11, file descriptors 0, 1, and 2 are connected to a terminal device, and each of them is opened for both reading and writing. This is the case despite the fact that one normally only reads from fd 0 and writes to fd 1 and 2.
Yet here is the code from 7th edition init.c:
open(tty, 2);
dup(0);
dup(0);
...
execl(getty, minus, tty, (char *)0);
And here is how ssh
does it:
ioctl(*ttyfd, TCSETCTTY, NULL);
fd = open("/dev/tty", O_RDWR);
if (fd < 0)
error("%.100s: %.100s", tty, strerror(errno));
close(*ttyfd);
*ttyfd = fd;
...
/* Redirect stdin/stdout/stderr from the pseudo tty. */
if (dup2(ttyfd, 0) < 0)
error("dup2 stdin: %s", strerror(errno));
if (dup2(ttyfd, 1) < 0)
error("dup2 stdout: %s", strerror(errno));
if (dup2(ttyfd, 2) < 0)
error("dup2 stderr: %s", strerror(errno));
(The dup2
function dups arg1 into arg2, closing arg2 first if necessary.)
And here is how xterm
does it:
if ((ttyfd = open(ttydev, O_RDWR)) >= 0) {
/* make /dev/tty work */
ioctl(ttyfd, TCSETCTTY, 0);
...
/* this is the time to go and set up stdin, out, and err
*/
{
/* dup the tty */
for (i = 0; i <= 2; i++)
if (i != ttyfd) {
IGNORE_RC(close(i));
IGNORE_RC(dup(ttyfd));
}
/* and close the tty */
if (ttyfd > 2)
close_fd(ttyfd);
Back to your code.
close(fileno(stdout));
This closes fd 1.
int fd = dup(fileno(stdin));
This duplicates fd 0 into the lowest available fd, which is 1, and assigns 1 to fd
. (This assumes that fd 0 is open, of course.) Both fd's 0 and 1 are now open for reading and writing (assuming they're connected to a terminal device). On a Linux system you can verify this:
$ cat /proc/self/fdinfo/0
pos: 0
flags: 0100002
mnt_id: 20
$ cat /proc/self/fdinfo/1
pos: 0
flags: 0100002
mnt_id: 20
The 2
in flags
, which is the constant O_RDWR
, means open for reading and writing.
printf("Hello World\n");
This writes to fd 1, which is, once again, open for reading and writing to your terminal.
write(fd, "Hello", 7);
This writes to fd 1 again. (Note that "Hello"
is only 6 bytes, though.)
Upvotes: 5
Reputation: 239011
If you are running your program on a terminal, then stdin
and stdout
are opens of the same file - your terminal device. So it should not be surprising that writing to stdin
- or a dup()
of fileno(stdin)
- writes to your terminal device, and you see it.
If you run your program with stdin
connected somewhere else, like a disk file, you'll see a different result:
./program < file
Upvotes: 4