commit: ce1173fe24f8466a23c502a52af38cdab42353a2 Author: Brian Harring <ferringb <AT> gmail <DOT> com> AuthorDate: Sat Dec 24 22:23:54 2022 +0000 Commit: Arthur Zamarin <arthurzam <AT> gentoo <DOT> org> CommitDate: Sun Dec 25 17:40:11 2022 +0000 URL: https://gitweb.gentoo.org/proj/pkgcore/pkgcore.git/commit/?id=ce1173fe
Fix secondary exception from when an EBD fails to start. Further in this __init__, self.pid is initialized to the process that is started. If that fails- an exception is thrown- then self.pid doesn't exist, which in turn breaks the assumptions of `shutdown_processor()` and `.is_alive` (both of which are designed to work if an init partially failed). Finally, add protections to ensure a failed spawn doesn't leak file descriptors. Python won't reap raw FD's, so we need to handle this gracefully. This secondary exception is visible in pkgcore/pkgcore#296 Signed-off-by: Brian Harring <ferringb <AT> gmail.com> Closes: https://github.com/pkgcore/pkgcore/pull/383 Signed-off-by: Arthur Zamarin <arthurzam <AT> gentoo.org> src/pkgcore/ebuild/processor.py | 49 ++++++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/src/pkgcore/ebuild/processor.py b/src/pkgcore/ebuild/processor.py index 6157ad692..8e9bf13cd 100644 --- a/src/pkgcore/ebuild/processor.py +++ b/src/pkgcore/ebuild/processor.py @@ -324,6 +324,7 @@ class EbuildProcessor: self._eclass_caching = False self._outstanding_expects = [] self._metadata_paths = None + self.pid = None spawn_opts = {'umask': 0o002} if self.userpriv: @@ -371,25 +372,37 @@ class EbuildProcessor: "PKGCORE_EBD_WRITE_FD": str(max_fd - 3), }) + cread = cwrite = dread = dwrite = None # open pipes used for communication - cread, cwrite = os.pipe() - dread, dwrite = os.pipe() - - # allow pipe overrides except ebd-related - ebd_pipes = {0: 0, 1: 1, 2: 2} - if fd_pipes: - ebd_pipes.update(fd_pipes) - ebd_pipes[max_fd - 4] = cread - ebd_pipes[max_fd - 3] = dwrite - - # force each ebd instance to be a process group leader so everything - # can be easily terminated - self.pid = spawn_func( - [spawn.BASH_BINARY, self.ebd, "daemonize"], - fd_pipes=ebd_pipes, returnpid=True, env=env, pgid=0, **spawn_opts)[0] - - os.close(cread) - os.close(dwrite) + try: + cread, cwrite = os.pipe() + dread, dwrite = os.pipe() + + # allow pipe overrides except ebd-related + ebd_pipes = {0: 0, 1: 1, 2: 2} + if fd_pipes: + ebd_pipes.update(fd_pipes) + ebd_pipes[max_fd - 4] = cread + ebd_pipes[max_fd - 3] = dwrite + + self.pid = spawn_func( + [spawn.BASH_BINARY, self.ebd, "daemonize"], + fd_pipes=ebd_pipes, returnpid=True, env=env, + # force each ebd instance to be a process group leader so everything + # can be easily terminated + pgid=0, + **spawn_opts)[0] + except: + if cwrite is not None: + os.close(cwrite) + if dread is not None: + os.close(dread) + raise + finally: + if cread is not None: + os.close(cread) + if dwrite is not None: + os.close(dwrite) self.ebd_write = os.fdopen(cwrite, "w") self.ebd_read = os.fdopen(dread, "r")
