简体   繁体   中英

Explanation on dup syscall

  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

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

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.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM