Yesterday I polled people on whether opening /dev/fd/N should act as if you'd dup()'d that file descriptor. The answer is 'no, that's terrifying'.
When you dup() file descriptors, the two fds share a bunch of state, especially including the IO offset in the file; meanwhile, open() promises a file descriptor with independent state. So turning open() into dup() may cause all sorts of fun surprises as changes to the current offset and other things on one fd are magically also on the other.
@lanodan I'm actually a bit curious about whether there's a deep reason for that dup() behavior or if it started as an artifact of an easy implementation (just increase the reference count on a file object in the kernel, no need to copy it and do stuff and etc etc). Especially since early Unixes had small limits on things like total open files; dup()'s sharing reduced pressure on them.
I don't mean that implementation requires that, but that I don't see what semantics you could assign to two independent opens of the same end of the same pipe.
(Actually, the problem is even worse with Unix sockets: server side was not created on request, so you can't really do anything other than moral equivalent of dup; client-side was not created via open() *and* the file/abstract name that was dialed could no longer be accessible.)
Ah, I see, you are proposing something that would still function as the "same open" for all intents and purposes but not share flags (or file pointers, but you mentioned that this would break appending to shared std{out,err}). I think I agree that sharing of O_NONBLOCK and other flags I can think of makes no sense.
I wonder why O_NONBLOCK is a FL-flag and not an FD-flag.
@robryk @lanodan Pipes and sockets are already sort of special, since you can't seek on them. However there are probably some attributes that are useful to set separately on instances of pipes (and sockets), like O_NONBLOCK (although I can't remember if that was in V7, not that sockets were).