Permalink
Browse files

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.
  • Loading branch information...
1 parent 4a88b3b commit 27cd5f03ef26b32b0043ae67bb2dae9dabda60bf @bnoordhuis bnoordhuis committed Jun 29, 2012
Showing with 19 additions and 7 deletions.
  1. +19 −7 src/unix/linux/syscalls.c
View
@@ -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

0 comments on commit 27cd5f0

Please sign in to comment.