aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'lib/portage/util/_async/BuildLogger.py')
-rw-r--r--lib/portage/util/_async/BuildLogger.py41
1 files changed, 37 insertions, 4 deletions
diff --git a/lib/portage/util/_async/BuildLogger.py b/lib/portage/util/_async/BuildLogger.py
index cbed2d811..0cfc90a94 100644
--- a/lib/portage/util/_async/BuildLogger.py
+++ b/lib/portage/util/_async/BuildLogger.py
@@ -1,4 +1,4 @@
-# Copyright 2020-2021 Gentoo Authors
+# Copyright 2020-2024 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2
import functools
@@ -6,13 +6,46 @@ import subprocess
from _emerge.AsynchronousTask import AsynchronousTask
+import portage
from portage import os
+from portage.proxy.objectproxy import ObjectProxy
from portage.util import shlex_split
from portage.util._async.PipeLogger import PipeLogger
from portage.util._async.PopenProcess import PopenProcess
from portage.util.futures import asyncio
+class _file_close_wrapper(ObjectProxy):
+ """
+ Prevent fd inheritance via fork, ensuring that we can observe
+ EOF on the read end of the pipe (bug 919072).
+ """
+
+ __slots__ = ("_file",)
+
+ def __init__(self, file):
+ ObjectProxy.__init__(self)
+ object.__setattr__(self, "_file", file)
+ portage.locks._open_fds[file.fileno()] = self
+
+ def _get_target(self):
+ return object.__getattribute__(self, "_file")
+
+ def __getattribute__(self, attr):
+ if attr == "close":
+ return object.__getattribute__(self, attr)
+ return getattr(object.__getattribute__(self, "_file"), attr)
+
+ def close(self):
+ file = object.__getattribute__(self, "_file")
+ if not file.closed:
+ # This must only be called if the file is open,
+ # which ensures that file.fileno() does not
+ # collide with an open lock file descriptor.
+ del portage.locks._open_fds[file.fileno()]
+ file.close()
+
+
class BuildLogger(AsynchronousTask):
"""
Write to a log file, with compression support provided by PipeLogger.
@@ -60,14 +93,14 @@ class BuildLogger(AsynchronousTask):
scheduler=self.scheduler,
)
filter_proc.start()
- except EnvironmentError:
+ except OSError:
# Maybe the command is missing or broken somehow...
os.close(filter_input)
os.close(stdin)
os.close(log_input)
os.close(filter_output)
else:
- self._stdin = os.fdopen(stdin, "wb", 0)
+ self._stdin = _file_close_wrapper(os.fdopen(stdin, "wb", 0))
os.close(filter_input)
os.close(filter_output)
@@ -76,7 +109,7 @@ class BuildLogger(AsynchronousTask):
# that is missing or broken somehow, create a pipe that
# logs directly to pipe_logger.
log_input, stdin = os.pipe()
- self._stdin = os.fdopen(stdin, "wb", 0)
+ self._stdin = _file_close_wrapper(os.fdopen(stdin, "wb", 0))
# Set background=True so that pipe_logger does not log to stdout.
pipe_logger = PipeLogger(