1

Here is a code snippet.

int saved_stdout = dup(1);
int fd = open("file.txt", O_WRONLY | O_CREAT, 0640);

close(1);
dup(fd);
close(fd);

printf("This text should go into the file\n");

//restore stdout
dup2(saved_stdout, 1);
printf("stdout restore");

I am trying to learn about dup and dup2. So I initially connected my file.txt to stdout. So whenever I use printf, I should be writing to file.txt instead of stdout. But I want to restore it back as well once I am done with this usage, so I use dup2 at the end as well.

The problem is that the text "This text should go into the file\n" never actually goes into the file, but gets printed on stdout. Why so? I straced for it, only to find that dup2 call occurs before that printf("This text..."); statement, why so?

posixKing
  • 408
  • 1
  • 8
  • 17

2 Answers2

5

The problem may be due to output buffering. stdout is fully buffered if it's not writing to a terminal, so when you redirect it to the file with dup() it will be buffered. Try flushing the output after the printf().

printf("This text should go into the file\n");
fflush(stdout);
Barmar
  • 741,623
  • 53
  • 500
  • 612
  • This is what I was looking for. Thanks – posixKing Dec 07 '16 at 22:55
  • While `fflush()` "works", I suspect it's for the wrong reason. There's something more subtle going on here, as simply putting any `printf()` immediately after the `open()` also works. The problem is the mixing of file descriptors and FILE structures, which is perhaps undefined territory, meaning you might get different results on different systems. The correct way to do what you want is to `freopen("file.txt", "w", stdout)`. That operation is clearly defined. – gilez Dec 08 '16 at 00:56
  • @gilez I think as long as you flush between writing something and changing the file descriptor, you should be safe. Although I admit I'm a little hesitant with this answer, because I suspect that the buffering is initialized when `stdin` is opened, not when `printf()` occurs. But it could be lazy and do it at the first write. – Barmar Dec 08 '16 at 01:00
  • @Barmar, I suspect the stdout `FILE *` is somehow not initialized completely until used, so the order of operations matters too, and my `printf()` option thus makes it "work". You could be correct about the buffering too. It's all a bit dodgy :-) – gilez Dec 08 '16 at 01:31
0

I removed my prior answer as it's wrong.... But when you use printf() you're using the FILE * for stdout, inside of which there's a descriptor or something pointing to the terminal. Changing fd 1 is apparently not changing that.

I'm getting inconsistent results with testing, so giving up here. I just want to add that putting this line just after the open() makes it work for me, which highlights the obscure behaviour:

printf("fileno is %i\n", fileno(stdout));

Don't mix FILE * operations such as printf() with file descriptor manipulation. You should use write() with the descriptor.

gilez
  • 669
  • 3
  • 6
  • 1
    `dup()` does use the first available descriptor. His code is how things were done before `dup2()` was added. – Barmar Dec 07 '16 at 22:48
  • @Barmar, I think the confusion is over what "first available" means. Is it 1 because that's closed, or 4 because that's never been used? – gilez Dec 07 '16 at 22:55
  • @posixKing, turns out it's using 4 on my system, and perhaps OP's. Why "should"? On linux the description in the man page is not precise. – gilez Dec 07 '16 at 22:57
  • On my system (OS X) the man page says "the lowest numbered descriptor currently not in use by the process." – Barmar Dec 07 '16 at 22:58
  • @Barmar, that is similar to my Linux system. But it's not doing what we seem to expect. Does it open 1 or 4 on your system? See http://pastebin.com/tQbGrMLe for a compilable copy. – gilez Dec 07 '16 at 23:01
  • Your program prints `fd`, not what `dup()` returns. – Barmar Dec 07 '16 at 23:03
  • However, you're right that `dup2()` is preferred. Otherwise, you have to depend on knowing that `stdin` hasn't been closed. – Barmar Dec 07 '16 at 23:08