dup2() redirect

I am a bit confused about dup2. I am trying to redirect stdout to file and back.
It works with a fork(). I'm having trouble making it work without forking. Closing file descriptors has something to do with it...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
int main()
{
        int pid;
        int fd;
	
        int defout = dup(1);
	fd=open("out.txt", O_RDWR | O_TRUNC | O_CREAT);
	dup2(fd, 1); // redirect output to the file
	
	pid = fork(); // create child
	if (!pid) // if pid==0 then its a child process
	{
		close(fd);
		close(defout);
		printf("to file\n");
                exit(0);
	}
        
	dup2(defout, 1); // redirect output back to stdout
	close(fd);
	close(defout);
	
	wait(NULL); // wait until child finishes
	printf("to stdout\n");
}


So what does close have to do with anything?
IIRC, the child has inherits the same file descriptors, so if you close them then you will be closing them for all the children too. (Not totally sure on this though).
I think your problem arises from mixing stdio routines with basic operating system IO functions. Try the following code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main()
{
    int fd;
    int defout;
 
    if ((defout = dup(1)) < 0)
    {
        fprintf(stderr, "Can't dup(2) - (%s)\n", strerror(errno));
        exit(1);
    }
    if ((fd = open("out.txt", O_RDWR | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR)) < 0)
    {
        fprintf(stderr, "Can't open(2) - (%s)\n", strerror(errno));
        exit(1);
    }
    if (dup2(fd, 1) < 0) // redirect output to the file
    {
        fprintf(stderr, "Can't dup2(2) - (%s)\n", strerror(errno));
        exit(1);
    }
    close(fd);  // Descriptor no longer needed

    if (printf("to file\n") < 0)
    {
        fprintf(stderr, "Can't printf(3) to fd=%d - (%s)\n", fileno(stdout), strerror(errno));
        exit(1);
    }

    fflush(stdout);          // FLUSH ALL OUTPUT TO "out.txt"
    // Now stdout is clean for another target

    if (dup2(defout, 1) < 0) // redirect output back to stdout
    {
        fprintf(stderr, "Can't dup2(2) - (%s)\n", strerror(errno));
        exit(1);
    }
    close(defout);  // Copy of stdout no longer needed
    
    if (printf("to stdout\n") < 0)
    {
        fprintf(stderr, "Can't printf(3) to fd=%d - (%s)\n", fileno(stdout), strerror(errno));
        exit(1);
    }
}


Besides some error handling I've added fflush(stdout); in line 37. Without it both printf(3) statements would write to the same FILE output buffer, namely those of "stdout" which is big enough to not being flushed by your two printf(3) statements. So its entire contents would finally be flushed on process exit to the file associated with fd=1 on process start. This would usually be your tty.


Your original code (using fork(2)) worked well, because fork(2) duplicates the FILE "stdout". So you've two buffers - one associated with "out.txt" and the other usually with your tty.
Last edited on
Topic archived. No new replies allowed.