From 27cd5f03ef26b32b0043ae67bb2dae9dabda60bf Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 29 Jun 2012 02:11:38 +0200 Subject: [PATCH] linux: fix accept4() ENOSYS detection on i386 accept4() piggybacks on the socketcall() on i386. socketcall() has the flaw that it returns EINVAL instead of ENOSYS when the operation is not supported. The problem is that accept4() also returns EINVAL when its flag argument is invalid. Try to discern between the two failure cases to the best of our abilities. --- src/unix/linux/syscalls.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/unix/linux/syscalls.c b/src/unix/linux/syscalls.c index 5eb826b7c..cbf2bbbde 100644 --- a/src/unix/linux/syscalls.c +++ b/src/unix/linux/syscalls.c @@ -152,13 +152,25 @@ int uv__accept4(int fd, struct sockaddr* addr, socklen_t* addrlen, int flags) { #if __i386__ - unsigned long args[] = { - (unsigned long) fd, - (unsigned long) addr, - (unsigned long) addrlen, - (unsigned long) flags - }; - return syscall(__NR_socketcall, 18 /* SYS_ACCEPT4 */, args); + unsigned long args[4]; + int r; + + args[0] = (unsigned long) fd; + args[1] = (unsigned long) addr; + args[2] = (unsigned long) addrlen; + args[3] = (unsigned long) flags; + + r = syscall(__NR_socketcall, 18 /* SYS_ACCEPT4 */, args); + + /* socketcall() raises EINVAL when SYS_ACCEPT4 is not supported but so does + * a bad flags argument. Try to distinguish between the two cases. + */ + if (r == -1) + if (errno == EINVAL) + if ((flags & ~(UV__SOCK_CLOEXEC|UV__SOCK_NONBLOCK)) == 0) + errno = ENOSYS; + + return r; #elif __NR_accept4 return syscall(__NR_accept4, fd, addr, addrlen, flags); #else