C – Shell redirection does not move the file location for standard output

Shell redirection does not move the file location for standard output… here is a solution to the problem.

Shell redirection does not move the file location for standard output

I have a minimal complete example where the Linux API behavior seems a bit ambiguous. Standard output is closed, reopened, and used as a descriptor for regular files:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>

int main(void) {
     system("echo > testfile");
     fclose(stdout);
     int fd = open("testfile", O_WRONLY);
     if (fd < 0) {
          perror("open():");
          return -1;
     }

dprintf(fd, "Test\n");
     system("echo Test2");
     system("echo TestFFFFFFFFFFFF >> /proc/$$/fd/1");  problem line
     sleep(5);
     dprintf(fd, "Test4\n");
     system("echo Test5");

return 0;
}

I saw it before testfile sleep

Test
Test2
TestFFFFFFFFFFFF

But after sleep this line is overwritten:

Test
Test2
Test4
Test5
FFFF

For ordinary files, this behavior seems strange: if we write something to the file – we change its position in an appropriate way (to the end).
But for stdout, it seems reasonable: if we write stdout – we rewind to its position when we finish writing (to start).
Is this the wrong or the right approach?

P.S. In addition to bash, I tried dash and ksh – the same thing.

Solution

The question is:

Is this a bug or the right way?

This is the right approach.


/

proc/$$/fd/1 is the symbolic link to the testfile, so >>/proc/$$/fd/1 is the same as >> testfile. It is a separate child process that writes testfile. When this child process terminates, you see what it writes to the file. It has no effect on your parent process.

STDOUT_FILENO is not special, it is just like any other file descriptor.

Why does a child process affect your parent process file descriptor location? Because duplicated file description tors refer to the same open file description tion. Read it twice – “file descriptor”!=”file description”. It’s like a double mapping. We say that file descriptors tors are not copied, they are duplicates, they share file offsets and file status flags because they share file descriptions. See man 2 dup and man 2 open.

When a separate process opens the same file, it has a separate file description, so it doesn’t affect your process file description.

(Its name is terrible.) I mentally refer to the “file descriptor” as a “system handle” (because it can refer to anything the kernel wants) and the “file description” as “file data” (if it’s a file, it can be anything the kernel wants). It’s obvious – this “system handle” refers to this “file data”, and “system handles” are duplicated between processes, which means that both “system handles” refer to the same open “file data”. File Data stores file locations, file locks, and more. Processes have “handles”, not “data”. “File data” is automatically deleted when the last “system handle” is deleted (confusing man 2 unlink). )

Related Problems and Solutions