724
724
PyDoc_STRVAR(subprocess_cloexec_pipe_doc,
725
725
"cloexec_pipe() -> (read_end, write_end)\n\n\
726
Create a pipe whose ends have the cloexec flag set.");
726
Create a pipe whose ends have the cloexec flag set; write_end will be >= 3.");
728
728
static PyObject *
729
729
subprocess_cloexec_pipe(PyObject *self, PyObject *noargs)
732
int res, saved_errno;
733
734
#ifdef HAVE_PIPE2
734
735
Py_BEGIN_ALLOW_THREADS
735
736
res = pipe2(fds, O_CLOEXEC);
736
737
Py_END_ALLOW_THREADS
737
738
if (res != 0 && errno == ENOSYS)
741
741
/* We hold the GIL which offers some protection from other code calling
742
742
* fork() before the CLOEXEC flags have been set but we can't guarantee
743
743
* anything without pipe2(). */
760
758
res = fcntl(fds[1], F_SETFD, oldflags | FD_CLOEXEC);
761
759
#ifdef HAVE_PIPE2
762
if (res == 0 && fds[1] < 3) {
763
/* We always want the write end of the pipe to avoid fds 0, 1 and 2
764
* as our child may claim those for stdio connections. */
765
int write_fd = fds[1];
766
int fds_to_close[3] = {-1, -1, -1};
767
int fds_to_close_idx = 0;
768
#ifdef F_DUPFD_CLOEXEC
769
fds_to_close[fds_to_close_idx++] = write_fd;
770
write_fd = fcntl(write_fd, F_DUPFD_CLOEXEC, 3);
771
if (write_fd < 0) /* We don't support F_DUPFD_CLOEXEC / other error */
774
/* Use dup a few times until we get a desirable fd. */
775
for (; fds_to_close_idx < 3; ++fds_to_close_idx) {
776
fds_to_close[fds_to_close_idx] = write_fd;
777
write_fd = dup(write_fd);
780
/* We may dup a few extra times if it returns an error but
781
* that is okay. Repeat calls should return the same error. */
783
if (write_fd < 0) res = write_fd;
785
oldflags = fcntl(write_fd, F_GETFD, 0);
786
if (oldflags < 0) res = oldflags;
788
res = fcntl(write_fd, F_SETFD, oldflags | FD_CLOEXEC);
792
/* Close fds we tried for the write end that were too low. */
793
for (fds_to_close_idx=0; fds_to_close_idx < 3; ++fds_to_close_idx) {
794
int temp_fd = fds_to_close[fds_to_close_idx];
795
while (temp_fd >= 0 && close(temp_fd) < 0 && errno == EINTR);
797
errno = saved_errno; /* report dup or fcntl errors, not close. */
799
} /* end if write fd was too small */
766
802
return PyErr_SetFromErrno(PyExc_OSError);
767
803
return Py_BuildValue("(ii)", fds[0], fds[1]);