fork · read · lseek
The cursor your child moves
fork copies the descriptor table and shares the descriptions underneath it. The child's read moves the parent's cursor, and nothing in the source says so.
`O_APPEND` is not a property of the write
O_APPEND lives on the description, and it means the seek-to-the-end happens inside the write, atomically. Two processes appending to one log never overwrite each other, however they are scheduled.
The tempting alternative — lseek to the end, then write — is two calls with a gap between them, and something else can append in that gap. It works every time you test it and fails under load, which is the worst kind of bug there is.
#include <fcntl.h>
#include <unistd.h>
int main(void) {
int a = open("/work/log", O_WRONLY|O_CREAT|O_APPEND, 0644);
int b = open("/work/log", O_WRONLY|O_CREAT|O_APPEND, 0644);
write(a, "one\n", 4);
write(b, "two\n", 4);
close(a);
close(b);
return 0;
}Watch: Two descriptions with two cursors, and nothing lost. The flag is on the description, not the write.