From 30c652a9db1014fc720f7d6055520a07b731c984 Mon Sep 17 00:00:00 2001
From: Zac Medico <zmedico@gentoo.org>
Date: Sun, 1 Sep 2013 12:37:58 -0700
Subject: [PATCH] Use F_GETFD/F_SETFD for FD_CLOEXEC.

This mixup may have caused bug #456296 (see commit
e43524dc88774f768441dcb386a534166a53f7fa).
---
 pym/_emerge/AsynchronousLock.py          |  9 +++++----
 pym/_emerge/EbuildMetadataPhase.py       | 10 +++++-----
 pym/_emerge/FifoIpcDaemon.py             |  8 ++++----
 pym/_emerge/PipeReader.py                | 17 ++++++++---------
 pym/_emerge/SpawnProcess.py              | 10 +++++++---
 pym/portage/dbapi/_MergeProcess.py       |  9 +++++----
 pym/portage/locks.py                     |  4 ++--
 pym/portage/util/_async/PipeLogger.py    | 18 +++++++++---------
 pym/portage/util/_eventloop/EventLoop.py | 17 +++++++++--------
 9 files changed, 54 insertions(+), 48 deletions(-)

diff --git a/pym/_emerge/AsynchronousLock.py b/pym/_emerge/AsynchronousLock.py
index c2dbf2d3c..cfe98b09f 100644
--- a/pym/_emerge/AsynchronousLock.py
+++ b/pym/_emerge/AsynchronousLock.py
@@ -165,16 +165,17 @@ class _LockProcess(AbstractPollTask):
 		self._files['pipe_in'] = in_pr
 		self._files['pipe_out'] = out_pw
 
-		fcntl_flags = os.O_NONBLOCK
+		fcntl.fcntl(in_pr, fcntl.F_SETFL,
+			fcntl.fcntl(in_pr, fcntl.F_GETFL) | os.O_NONBLOCK)
+
 		try:
 			fcntl.FD_CLOEXEC
 		except AttributeError:
 			pass
 		else:
-			fcntl_flags |= fcntl.FD_CLOEXEC
+			fcntl.fcntl(in_pr, fcntl.F_SETFD,
+				fcntl.fcntl(in_pr, fcntl.F_GETFD) | fcntl.FD_CLOEXEC)
 
-		fcntl.fcntl(in_pr, fcntl.F_SETFL,
-			fcntl.fcntl(in_pr, fcntl.F_GETFL) | fcntl_flags)
 		self._reg_id = self.scheduler.io_add_watch(in_pr,
 			self.scheduler.IO_IN, self._output_handler)
 		self._registered = True
diff --git a/pym/_emerge/EbuildMetadataPhase.py b/pym/_emerge/EbuildMetadataPhase.py
index 7418aba9f..7882b6369 100644
--- a/pym/_emerge/EbuildMetadataPhase.py
+++ b/pym/_emerge/EbuildMetadataPhase.py
@@ -91,16 +91,16 @@ class EbuildMetadataPhase(SubProcess):
 
 		master_fd, slave_fd = os.pipe()
 
-		fcntl_flags = os.O_NONBLOCK
+		fcntl.fcntl(master_fd, fcntl.F_SETFL,
+			fcntl.fcntl(master_fd, fcntl.F_GETFL) | os.O_NONBLOCK)
+
 		try:
 			fcntl.FD_CLOEXEC
 		except AttributeError:
 			pass
 		else:
-			fcntl_flags |= fcntl.FD_CLOEXEC
-
-		fcntl.fcntl(master_fd, fcntl.F_SETFL,
-			fcntl.fcntl(master_fd, fcntl.F_GETFL) | fcntl_flags)
+			fcntl.fcntl(master_fd, fcntl.F_SETFD,
+				fcntl.fcntl(master_fd, fcntl.F_GETFD) | fcntl.FD_CLOEXEC)
 
 		fd_pipes[slave_fd] = slave_fd
 		settings["PORTAGE_PIPE_FD"] = str(slave_fd)
diff --git a/pym/_emerge/FifoIpcDaemon.py b/pym/_emerge/FifoIpcDaemon.py
index 113e49da8..662aec11c 100644
--- a/pym/_emerge/FifoIpcDaemon.py
+++ b/pym/_emerge/FifoIpcDaemon.py
@@ -33,9 +33,9 @@ class FifoIpcDaemon(AbstractPollTask):
 			except AttributeError:
 				pass
 			else:
-				fcntl.fcntl(self._files.pipe_in, fcntl.F_SETFL,
+				fcntl.fcntl(self._files.pipe_in, fcntl.F_SETFD,
 					fcntl.fcntl(self._files.pipe_in,
-						fcntl.F_GETFL) | fcntl.FD_CLOEXEC)
+						fcntl.F_GETFD) | fcntl.FD_CLOEXEC)
 
 		self._reg_id = self.scheduler.io_add_watch(
 			self._files.pipe_in,
@@ -59,9 +59,9 @@ class FifoIpcDaemon(AbstractPollTask):
 			except AttributeError:
 				pass
 			else:
-				fcntl.fcntl(self._files.pipe_in, fcntl.F_SETFL,
+				fcntl.fcntl(self._files.pipe_in, fcntl.F_SETFD,
 					fcntl.fcntl(self._files.pipe_in,
-						fcntl.F_GETFL) | fcntl.FD_CLOEXEC)
+						fcntl.F_GETFD) | fcntl.FD_CLOEXEC)
 
 		self._reg_id = self.scheduler.io_add_watch(
 			self._files.pipe_in,
diff --git a/pym/_emerge/PipeReader.py b/pym/_emerge/PipeReader.py
index be93be323..c7eef1d79 100644
--- a/pym/_emerge/PipeReader.py
+++ b/pym/_emerge/PipeReader.py
@@ -26,18 +26,17 @@ class PipeReader(AbstractPollTask):
 		else:
 			output_handler = self._output_handler
 
-		fcntl_flags = os.O_NONBLOCK
-		try:
-			fcntl.FD_CLOEXEC
-		except AttributeError:
-			pass
-		else:
-			fcntl_flags |= fcntl.FD_CLOEXEC
-
 		for f in self.input_files.values():
 			fd = isinstance(f, int) and f or f.fileno()
 			fcntl.fcntl(fd, fcntl.F_SETFL,
-				fcntl.fcntl(fd, fcntl.F_GETFL) | fcntl_flags)
+				fcntl.fcntl(fd, fcntl.F_GETFL) | os.O_NONBLOCK)
+			try:
+				fcntl.FD_CLOEXEC
+			except AttributeError:
+				pass
+			else:
+				fcntl.fcntl(fd, fcntl.F_SETFD,
+					fcntl.fcntl(fd, fcntl.F_GETFD) | fcntl.FD_CLOEXEC)
 			self._reg_ids.add(self.scheduler.io_add_watch(fd,
 				self._registered_events, output_handler))
 		self._registered = True
diff --git a/pym/_emerge/SpawnProcess.py b/pym/_emerge/SpawnProcess.py
index 994f3ddbb..2c2e1a982 100644
--- a/pym/_emerge/SpawnProcess.py
+++ b/pym/_emerge/SpawnProcess.py
@@ -19,6 +19,8 @@ from portage.const import BASH_BINARY
 from portage.util._async.PipeLogger import PipeLogger
 
 # On Darwin, FD_CLOEXEC triggers errno 35 for stdout (bug #456296)
+# TODO: Test this again now that it's been fixed to use
+# F_GETFD/F_SETFD instead of F_GETFL/F_SETFL.
 _disable_cloexec_stdout = platform.system() in ("Darwin",)
 
 class SpawnProcess(SubProcess):
@@ -130,12 +132,14 @@ class SpawnProcess(SubProcess):
 					pass
 				else:
 					try:
-						fcntl.fcntl(stdout_fd, fcntl.F_SETFL,
+						fcntl.fcntl(stdout_fd, fcntl.F_SETFD,
 							fcntl.fcntl(stdout_fd,
-							fcntl.F_GETFL) | fcntl.FD_CLOEXEC)
+							fcntl.F_GETFD) | fcntl.FD_CLOEXEC)
 					except IOError:
 						# FreeBSD may return "Inappropriate ioctl for device"
-						# error here (ENOTTY).
+						# error here (ENOTTY). TODO: Test this again now that
+						# it's been fixed to use F_GETFD/F_SETFD instead of
+						# F_GETFL/F_SETFL.
 						pass
 
 		self._pipe_logger = PipeLogger(background=self.background,
diff --git a/pym/portage/dbapi/_MergeProcess.py b/pym/portage/dbapi/_MergeProcess.py
index fba61e82f..d7280f082 100644
--- a/pym/portage/dbapi/_MergeProcess.py
+++ b/pym/portage/dbapi/_MergeProcess.py
@@ -117,16 +117,17 @@ class MergeProcess(ForkProcess):
 
 		elog_reader_fd, elog_writer_fd = os.pipe()
 
-		fcntl_flags = os.O_NONBLOCK
+		fcntl.fcntl(elog_reader_fd, fcntl.F_SETFL,
+			fcntl.fcntl(elog_reader_fd, fcntl.F_GETFL) | os.O_NONBLOCK)
+
 		try:
 			fcntl.FD_CLOEXEC
 		except AttributeError:
 			pass
 		else:
-			fcntl_flags |= fcntl.FD_CLOEXEC
+			fcntl.fcntl(elog_reader_fd, fcntl.F_SETFD,
+				fcntl.fcntl(elog_reader_fd, fcntl.F_GETFD) | fcntl.FD_CLOEXEC)
 
-		fcntl.fcntl(elog_reader_fd, fcntl.F_SETFL,
-			fcntl.fcntl(elog_reader_fd, fcntl.F_GETFL) | fcntl_flags)
 		blockers = None
 		if self.blockers is not None:
 			# Query blockers in the main process, since closing
diff --git a/pym/portage/locks.py b/pym/portage/locks.py
index 87aaf94a2..4f356c9c1 100644
--- a/pym/portage/locks.py
+++ b/pym/portage/locks.py
@@ -239,8 +239,8 @@ def lockfile(mypath, wantnewlockfile=0, unlinkfile=0,
 		except AttributeError:
 			pass
 		else:
-			fcntl.fcntl(myfd, fcntl.F_SETFL,
-				fcntl.fcntl(myfd, fcntl.F_GETFL) | fcntl.FD_CLOEXEC)
+			fcntl.fcntl(myfd, fcntl.F_SETFD,
+				fcntl.fcntl(myfd, fcntl.F_GETFD) | fcntl.FD_CLOEXEC)
 
 		_open_fds.add(myfd)
 
diff --git a/pym/portage/util/_async/PipeLogger.py b/pym/portage/util/_async/PipeLogger.py
index d0b132378..06d820097 100644
--- a/pym/portage/util/_async/PipeLogger.py
+++ b/pym/portage/util/_async/PipeLogger.py
@@ -38,21 +38,21 @@ class PipeLogger(AbstractPollTask):
 				uid=portage.portage_uid, gid=portage.portage_gid,
 				mode=0o660)
 
-		fcntl_flags = os.O_NONBLOCK
-		try:
-			fcntl.FD_CLOEXEC
-		except AttributeError:
-			pass
-		else:
-			fcntl_flags |= fcntl.FD_CLOEXEC
-
 		if isinstance(self.input_fd, int):
 			fd = self.input_fd
 		else:
 			fd = self.input_fd.fileno()
 
 		fcntl.fcntl(fd, fcntl.F_SETFL,
-			fcntl.fcntl(fd, fcntl.F_GETFL) | fcntl_flags)
+			fcntl.fcntl(fd, fcntl.F_GETFL) | os.O_NONBLOCK)
+
+		try:
+			fcntl.FD_CLOEXEC
+		except AttributeError:
+			pass
+		else:
+			fcntl.fcntl(fd, fcntl.F_SETFD,
+				fcntl.fcntl(fd, fcntl.F_GETFD) | fcntl.FD_CLOEXEC)
 
 		self._reg_id = self.scheduler.io_add_watch(fd,
 			self._registered_events, self._output_handler)
diff --git a/pym/portage/util/_eventloop/EventLoop.py b/pym/portage/util/_eventloop/EventLoop.py
index 3742055e9..46a1f09f9 100644
--- a/pym/portage/util/_eventloop/EventLoop.py
+++ b/pym/portage/util/_eventloop/EventLoop.py
@@ -91,9 +91,9 @@ class EventLoop(object):
 					except AttributeError:
 						pass
 					else:
-						fcntl.fcntl(epoll_obj.fileno(), fcntl.F_SETFL,
+						fcntl.fcntl(epoll_obj.fileno(), fcntl.F_SETFD,
 							fcntl.fcntl(epoll_obj.fileno(),
-								fcntl.F_GETFL) | fcntl.FD_CLOEXEC)
+								fcntl.F_GETFD) | fcntl.FD_CLOEXEC)
 
 				self._poll_obj = _epoll_adapter(epoll_obj)
 				self.IO_ERR = select.EPOLLERR
@@ -315,17 +315,18 @@ class EventLoop(object):
 			if self._sigchld_read is None:
 				self._sigchld_read, self._sigchld_write = os.pipe()
 
-				fcntl_flags = os.O_NONBLOCK
+				fcntl.fcntl(self._sigchld_read, fcntl.F_SETFL,
+					fcntl.fcntl(self._sigchld_read,
+					fcntl.F_GETFL) | os.O_NONBLOCK)
+
 				try:
 					fcntl.FD_CLOEXEC
 				except AttributeError:
 					pass
 				else:
-					fcntl_flags |= fcntl.FD_CLOEXEC
-
-				fcntl.fcntl(self._sigchld_read, fcntl.F_SETFL,
-					fcntl.fcntl(self._sigchld_read,
-					fcntl.F_GETFL) | fcntl_flags)
+					fcntl.fcntl(self._sigchld_read, fcntl.F_SETFD,
+						fcntl.fcntl(self._sigchld_read,
+						fcntl.F_GETFD) | fcntl.FD_CLOEXEC)
 
 			# The IO watch is dynamically registered and unregistered as
 			# needed, since we don't want to consider it as a valid source
-- 
2.26.2