provide emulation of fcntl F_DUPFD_CLOEXEC on old kernels
authorRich Felker <dalias@aerifal.cx>
Wed, 27 Mar 2013 02:54:57 +0000 (22:54 -0400)
committerRich Felker <dalias@aerifal.cx>
Wed, 27 Mar 2013 02:54:57 +0000 (22:54 -0400)
I'm not entirely happy with the amount of ugliness here, but since
F_DUPFD_CLOEXEC is used elsewhere in code that's expected to work on
old kernels (popen), it seems necessary. reportedly even some modern
kernels went back and broke F_DUPFD_CLOEXEC (making it behave like
plain F_DUPFD), so it might be necessary to add some additional fixup
code later to deal with that issue too.

src/fcntl/fcntl.c

index fb7806a..390ef75 100644 (file)
@@ -22,5 +22,21 @@ int fcntl(int fd, int cmd, ...)
                if (ret) return __syscall_ret(ret);
                return ex.type == F_OWNER_PGRP ? -ex.pid : ex.pid;
        }
+       if (cmd == F_DUPFD_CLOEXEC) {
+               int ret = __syscall(SYS_fcntl, fd, F_DUPFD_CLOEXEC, arg);
+               if (ret != -EINVAL) {
+                       if (ret >= 0)
+                               __syscall(SYS_fcntl, ret, F_SETFD, FD_CLOEXEC);
+                       return __syscall_ret(ret);
+               }
+               ret = __syscall(SYS_fcntl, fd, F_DUPFD_CLOEXEC, 0);
+               if (ret != -EINVAL) {
+                       if (ret >= 0) __syscall(SYS_close, ret);
+                       return __syscall_ret(-EINVAL);
+               }
+               ret = __syscall(SYS_fcntl, fd, F_DUPFD, arg);
+               if (ret >= 0) __syscall(SYS_fcntl, ret, F_SETFD, FD_CLOEXEC);
+               return __syscall_ret(ret);
+       }
        return syscall(SYS_fcntl, fd, cmd, arg);
 }