[PATCH] Mark fd's close-on-exec in qm.executable.

Nathaniel Smith njs at pobox.com
Thu Aug 14 08:17:33 UTC 2003


This patch marks all pipe fd's close-on-exec in
qm.executable.RedirectedExecutable.

-- Nathaniel

-- 
"If you can explain how you do something, then you're very very bad at it."
  -- John Hopfield
-------------- next part --------------
diff -urN --exclude='*~' --exclude='.*' --exclude=CVS --exclude='*.pyo' --exclude='*.pyc' --exclude=build --exclude=GNUmakefile --exclude=config.log --exclude=config.status --exclude=config.cache --exclude=qmtest --exclude=qm.spec --exclude='*.html' --exclude='*.dtd' --exclude=CATALOG --exclude=thread_target --exclude=process_target qm-clean/ChangeLog qm-close-fds/ChangeLog
--- qm-clean/ChangeLog	2003-08-14 01:12:49.000000000 -0700
+++ qm-close-fds/ChangeLog	2003-08-14 00:59:25.000000000 -0700
@@ -1,3 +1,11 @@
+2003-08-14  Nathaniel Smith  <njs at codesourcery.com>
+
+	* qm/executable.py (Executable._MakeCloseOnExec): New function.
+	(Executable.Run): Use it.
+	(RedirectedExecutable._CreatePipe): Use it; document that fds
+	will be closed on exec.  Add dup logic; document that returned
+	fds will always be >= 3.
+
 2003-08-13  Nathaniel Smith  <njs at codesourcery.com>
 
 	* qm/executable.py (Executable): Typo in docstring.
diff -urN --exclude='*~' --exclude='.*' --exclude=CVS --exclude='*.pyo' --exclude='*.pyc' --exclude=build --exclude=GNUmakefile --exclude=config.log --exclude=config.status --exclude=config.cache --exclude=qmtest --exclude=qm.spec --exclude='*.html' --exclude='*.dtd' --exclude=CATALOG --exclude=thread_target --exclude=process_target qm-clean/qm/executable.py qm-close-fds/qm/executable.py
--- qm-clean/qm/executable.py	2003-08-14 01:12:49.000000000 -0700
+++ qm-close-fds/qm/executable.py	2003-08-14 01:15:10.000000000 -0700
@@ -232,9 +232,7 @@
             exception_pipe = os.pipe()
             # Mark the write end as close-on-exec so that the file
             # descriptor is not passed on to the child.
-            fd = exception_pipe[1]
-            fcntl.fcntl(fd, fcntl.F_SETFD,
-                        fcntl.fcntl(fd, fcntl.F_GETFD) | fcntl.FD_CLOEXEC)
+            self._MakeCloseOnExec(exception_pipe[1])
         else:
             exception_pipe = None
 
@@ -324,6 +322,17 @@
         return self.__child
     
         
+    def _MakeCloseOnExec(self, fd):
+        """Modifies 'fd' to not be inherited across 'exec'.
+
+        UNIX only."""
+
+        assert sys.platform != "win32"
+
+        old_flags = fcntl.fcntl(fd, fcntl.F_GETFD)
+        fcntl.fcntl(fd, fcntl.F_SETFD, old_flags | fcntl.FD_CLOEXEC)
+
+
     def __CreateCommandLine(self, arguments):
         """Return a string giving the process command line.
 
@@ -772,7 +781,8 @@
         returns -- A tuple (under UNIX) or list (under Windows)
         consisting of the file descriptors (UNIX) or handles (Windows)
         for the read end and write end of a new pipe.  The pipe is
-        inheritable by child processes."""
+        inheritable by child processes.  On UNIX the fds will always be
+        >= 3 and in close-on-exec mode."""
 
         if sys.platform == "win32":
             # Create a security descriptor so that we can mark the handles
@@ -785,8 +795,20 @@
             r, w = win32pipe.CreatePipe(sa, 0)
             return [r, w]
         else:
-            return os.pipe()
-            
+            pipe = os.pipe()
+            for fd in pipe:
+                # Push the fd up above 2, to make sure it won't conflict
+                # with stdin/stdout/stderr.
+                closable = []
+                while fd <= 2:
+                    closable.append(fd)
+                    fd = os.dup(fd)
+                for old in closable:
+                    os.close(old)
+                # And make it close-on-exec.
+                self._MakeCloseOnExec(fd)
+            return pipe
+
 
     def __CallUntilNone(self, f, attribute):
         """Call 'f' until 'self.attribute' is 'None'.
Binary files qm-clean/results.qmr and qm-close-fds/results.qmr differ


More information about the qmtest mailing list