diff -ur py3k.ori/Lib/subprocess.py py3k/Lib/subprocess.py --- py3k.ori/Lib/subprocess.py 2011-01-04 19:07:07.000000000 +0000 +++ py3k/Lib/subprocess.py 2011-03-02 16:42:36.000000000 +0000 @@ -417,10 +417,6 @@ if mswindows: from _subprocess import CREATE_NEW_CONSOLE, CREATE_NEW_PROCESS_GROUP __all__.extend(["CREATE_NEW_CONSOLE", "CREATE_NEW_PROCESS_GROUP"]) -try: - MAXFD = os.sysconf("SC_OPEN_MAX") -except: - MAXFD = 256 _active = [] @@ -1112,8 +1108,7 @@ if fd >= start_fd: os.closerange(start_fd, fd) start_fd = fd + 1 - if start_fd <= MAXFD: - os.closerange(start_fd, MAXFD) + os.closefrom(start_fd) def _execute_child(self, args, executable, preexec_fn, close_fds, diff -ur py3k.ori/Lib/test/test_os.py py3k/Lib/test/test_os.py --- py3k.ori/Lib/test/test_os.py 2011-01-03 00:19:11.000000000 +0000 +++ py3k/Lib/test/test_os.py 2011-03-02 16:41:57.000000000 +0000 @@ -60,6 +60,22 @@ os.closerange(first, first + 2) self.assertRaises(OSError, os.write, first, b"a") + def test_closefrom(self): + # allocate a few file descriptors, close those smaller than min_fd, + # and then close all the remaining (greater than min_fd, to avoid + # closing stdin, stdout or stderr) with closefrom + min_fd = 7 + fd_list = [] + for i in range(10): + fd_list.append(os.open(support.TESTFN, os.O_CREAT|os.O_RDWR)) + for fd in fd_list: + if fd < min_fd: + os.close(fd) + # now, close all the remaining FD with closefrom + os.closefrom(min_fd) + for fd in fd_list: + self.assertRaises(OSError, os.write, fd, b"a") + @support.cpython_only def test_rename(self): path = support.TESTFN diff -ur py3k.ori/Modules/posixmodule.c py3k/Modules/posixmodule.c --- py3k.ori/Modules/posixmodule.c 2011-01-19 15:21:35.000000000 +0000 +++ py3k/Modules/posixmodule.c 2011-03-02 16:42:10.000000000 +0000 @@ -295,6 +295,9 @@ #endif #endif /* MAXPATHLEN */ +/* Maximum file descriptor, initialized on module load. */ +static int max_fd; + #ifdef UNION_WAIT /* Emulate some macros on systems that have a union instead of macros */ @@ -5557,6 +5560,50 @@ } +PyDoc_STRVAR(posix_closefrom__doc__, +"closefrom(fd_from)\n\n\ +Closes all file descriptors from fd_from, ignoring errors."); + +static PyObject * +posix_closefrom(PyObject *self, PyObject *args) +{ + int fd_from, i; +#ifndef MS_WINDOWS + DIR *dir; + struct dirent *dp; + long fd; +#endif + + if (!PyArg_ParseTuple(args, "i:closefrom", &fd_from)) + return NULL; + + Py_BEGIN_ALLOW_THREADS +#ifdef HAVE_CLOSEFROM + closefrom(fd_from); +#elif !defined(MS_WINDOWS) + /* Unix, see if /proc/self/fd is available */ + if ((dir = opendir("/proc/self/fd")) != NULL) { + while ((dp = readdir(dir)) != NULL) { + fd = strtol(dp->d_name, NULL, 0); + if (fd >= fd_from && fd <= INT_MAX && fd != dirfd(dir)) + close(fd); + } + closedir(dir); + } else { + /* /proc/self/fd not available, close FDs individually */ + for (i = fd_from; i < max_fd; i++) + close(i); + } +#else /* MS_WINDOWS, close FDs individually */ + for (i = fd_from; i < max_fd; i++) + if (_PyVerify_fd(i)) + close(i); +#endif + Py_END_ALLOW_THREADS + Py_RETURN_NONE; +} + + PyDoc_STRVAR(posix_dup__doc__, "dup(fd) -> fd2\n\n\ Return a duplicate of a file descriptor."); @@ -7965,6 +8012,7 @@ {"open", posix_open, METH_VARARGS, posix_open__doc__}, {"close", posix_close, METH_VARARGS, posix_close__doc__}, {"closerange", posix_closerange, METH_VARARGS, posix_closerange__doc__}, + {"closefrom", posix_closefrom, METH_VARARGS, posix_closefrom__doc__}, {"device_encoding", device_encoding, METH_VARARGS, device_encoding__doc__}, {"dup", posix_dup, METH_VARARGS, posix_dup__doc__}, {"dup2", posix_dup2, METH_VARARGS, posix_dup2__doc__}, @@ -8525,6 +8573,13 @@ #endif /* __APPLE__ */ + +#ifdef _SC_OPEN_MAX + max_fd = sysconf(_SC_OPEN_MAX); + if (max_fd == -1) +#endif + max_fd = 256; + return m; }