diff options
author | Rich Felker <dalias@aerifal.cx> | 2012-11-05 14:30:15 -0500 |
---|---|---|
committer | Rich Felker <dalias@aerifal.cx> | 2012-11-05 14:30:15 -0500 |
commit | e8a0b27a7101f5b9939de83df3d6d8b606c5678b (patch) | |
tree | 7545ed6491dff15ae0d71d38f778876b5e64d14f | |
parent | 32d6d77e544dbb1d9c44cacfc2ea0cbfe5ccfdef (diff) | |
download | musl-e8a0b27a7101f5b9939de83df3d6d8b606c5678b.tar.gz musl-e8a0b27a7101f5b9939de83df3d6d8b606c5678b.tar.bz2 musl-e8a0b27a7101f5b9939de83df3d6d8b606c5678b.tar.xz musl-e8a0b27a7101f5b9939de83df3d6d8b606c5678b.zip |
improve SOCK_NONBLOCK/SOCK_CLOEXEC fallback code
checking for EINVAL should be sufficient, but qemu user emulation
returns EPROTONOSUPPORT in some of the failure cases, and it seems
conceivable that other kernels doing linux-emulation could make the
same mistake. since DNS lookups and other important code might break
if the fallback does not get invoked, be extra careful and check for
either error.
note that it's important NOT to perform the fallback code on other
errors such as resource-exhaustion cases, since the fallback is not
atomic and will lead to file-descriptor leaks in multi-threaded
programs that use exec. the fallback code is only "safe" to run when
the initial failure is caused by the application's choice of
arguments, not the system state.
-rw-r--r-- | src/network/socket.c | 3 |
1 files changed, 2 insertions, 1 deletions
diff --git a/src/network/socket.c b/src/network/socket.c index ba8d45b1..51be30ee 100644 --- a/src/network/socket.c +++ b/src/network/socket.c @@ -6,7 +6,8 @@ int socket(int domain, int type, int protocol) { int s = socketcall(socket, domain, type, protocol, 0, 0, 0); - if (s<0 && errno==EINVAL && (type&(SOCK_CLOEXEC|SOCK_NONBLOCK))) { + if (s<0 && (errno==EINVAL || errno==EPROTONOSUPPORT) + && (type&(SOCK_CLOEXEC|SOCK_NONBLOCK))) { s = socketcall(socket, domain, type & ~(SOCK_CLOEXEC|SOCK_NONBLOCK), protocol, 0, 0, 0); |