Hi Bruno, On 5/18/24 3:42 AM, Bruno Haible wrote: > An interesting approach. But I think this added code comes too early: > In case of oldfd == newfd && newfd < 0, it would fail with EINVAL instead > of EBADF. > > How about trying the system call first, and test for newfd == oldfd only if > that system call succeeds?
Ah, I think you are right. The ordering is important. It looks like FreeBSD and OpenBSD behave as expected [1] [2]. Therefore I think it is best to #ifdef it for NetBSD. No need to perform the check elsewhere. How does this look? Passes tests on NetBSD 10.00. $ git diff . diff --git a/lib/dup3.c b/lib/dup3.c index a810d3be19..8c4e983df1 100644 --- a/lib/dup3.c +++ b/lib/dup3.c @@ -45,6 +45,15 @@ dup3 (int oldfd, int newfd, int flags) if (!(result < 0 && errno == ENOSYS)) { have_dup3_really = 1; + /* On NetBSD dup3 is a no-op when oldfd == newfd, but we expect + an error with errno == EINVAL. */ +# ifdef __NetBSD__ + if (newfd == oldfd) + { + errno = EINVAL; + return -1; + } +# endif # if REPLACE_FCHDIR if (0 <= result) result = _gl_register_dup (oldfd, newfd); Should I report this to the NetBSD people? I guess it isn't standardized so they are free to do as they wish. But it seems strange to behave differently then everyone else... Collin [1] https://man.freebsd.org/cgi/man.cgi?query=dup3&sektion=3 [2] https://man.openbsd.org/dup.2