In the following example we close default stderr
and reopen it on the temporary file via fdopen()
, using descriptor 2
, which was dup()
'ed from the temporary file descriptor. Then we write()
directly to this descriptor 2
. We can safely do this, because the is the first write operation on file and thus it has the empty buffer. After this, we fprintf()
to the new stderr
. Then we close stderr
(thus, its associated descriptor 2
is automatically closed). Original descriptor fd
remains valid. Through it we go to the beginning of the temporary file, read its contents and print them to stdout. But the output is garbled:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
int main(void)
{
int fd;
char buf[200];
int n;
char fname[] = "/tmp/tst-perror.XXXXXX";
fd = mkstemp (fname);
fclose (stderr);
dup2 (fd, 2);
stderr = fdopen (2, "w");
fd = fileno(stderr);
char *s = "this is a test\n";
n = write(fd, s, strlen(s));
fprintf(stderr, "multibyte string\n");
fclose (stderr);
// close(fd);
// fd = open(fname, O_RDONLY);
lseek (fd, 0, SEEK_SET);
n = read (fd, buf, sizeof (buf));
printf("%.*s", (int) n, buf);
close (fd);
return 0;
}
The output is:
$ ./a.out
����
If we uncomment the "close" and "open" lines and comment "lseek" line, the output is as expected:
$ ./a.out
this is a test
multibyte string
write()
does not have a buffer, and stderr
is written-off when it is closed, so
why the output is garbled if we do not close the file before reading it?
There is no check on return values from the functions. If it had been there you would have found the error.
Anyway, the issue is:
fd = fileno(stderr); // getting the fd from current stderr
fclose (stderr); // closing stderr
...
lseek (fd, 0, SEEK_SET); // seeking on fd which was already closed
In the last call and subsequent calls fd
is actually undefined (or rather it references closed file descriptor). Therefore any operation on fd
will fail EBADF
(not valid file descriptor).
Obviously if you include the fd = open(...)
again, fd
will become valid and the code will work.