~ubuntu-branches/ubuntu/utopic/python3.3/utopic

« back to all changes in this revision

Viewing changes to Modules/_posixsubprocess.c

  • Committer: Package Import Robot
  • Author(s): Matthias Klose
  • Date: 2014-01-27 12:13:57 UTC
  • mfrom: (1.2.11)
  • Revision ID: package-import@ubuntu.com-20140127121357-60ennw934dn1qirz
Tags: 3.3.4~rc1-1
Python 3.3.4 release candidate 1.

Show diffs side-by-side

added added

removed removed

Lines of Context:
723
723
 
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.");
727
727
 
728
728
static PyObject *
729
729
subprocess_cloexec_pipe(PyObject *self, PyObject *noargs)
730
730
{
731
731
    int fds[2];
732
 
    int res;
 
732
    int res, saved_errno;
 
733
    long oldflags;
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)
738
739
    {
739
 
        {
740
740
#endif
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(). */
744
 
        long oldflags;
745
 
 
746
744
        res = pipe(fds);
747
745
 
748
746
        if (res == 0) {
759
757
        if (res == 0)
760
758
            res = fcntl(fds[1], F_SETFD, oldflags | FD_CLOEXEC);
761
759
#ifdef HAVE_PIPE2
762
 
        }
763
760
    }
764
761
#endif
 
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 */
 
772
#endif
 
773
        {
 
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);
 
778
                if (write_fd >= 3)
 
779
                    break;
 
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. */
 
782
            }
 
783
            if (write_fd < 0) res = write_fd;
 
784
            if (res == 0) {
 
785
                oldflags = fcntl(write_fd, F_GETFD, 0);
 
786
                if (oldflags < 0) res = oldflags;
 
787
                if (res == 0)
 
788
                    res = fcntl(write_fd, F_SETFD, oldflags | FD_CLOEXEC);
 
789
            }
 
790
        }
 
791
        saved_errno = errno;
 
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);
 
796
        }
 
797
        errno = saved_errno;  /* report dup or fcntl errors, not close. */
 
798
        fds[1] = write_fd;
 
799
    }  /* end if write fd was too small */
 
800
 
765
801
    if (res != 0)
766
802
        return PyErr_SetFromErrno(PyExc_OSError);
767
803
    return Py_BuildValue("(ii)", fds[0], fds[1]);