Python is able to call sendmsg, it does not need a helper. Write the code directly; for now, keep the weird calling convention.
Signed-off-by: Paolo Bonzini <pbonz...@redhat.com> --- python/qemu/machine/machine.py | 48 ++++++++++++---------------------- python/qemu/qmp/__init__.py | 15 +++++++++++ 2 files changed, 32 insertions(+), 31 deletions(-) diff --git a/python/qemu/machine/machine.py b/python/qemu/machine/machine.py index 34131884a5..e4356ea99e 100644 --- a/python/qemu/machine/machine.py +++ b/python/qemu/machine/machine.py @@ -213,48 +213,34 @@ def add_fd(self: _T, fd: int, fdset: int, def send_fd_scm(self, fd: Optional[int] = None, file_path: Optional[str] = None) -> int: """ - Send an fd or file_path to socket_scm_helper. + Send an fd or file_path via QMP. Exactly one of fd and file_path must be given. - If it is file_path, the helper will open that file and pass its own fd. + If it is file_path, the function will open that file and pass + its own fd. """ # In iotest.py, the qmp should always use unix socket. assert self._qmp.is_scm_available() - if self._socket_scm_helper is None: - raise QEMUMachineError("No path to socket_scm_helper set") - if not os.path.exists(self._socket_scm_helper): - raise QEMUMachineError("%s does not exist" % - self._socket_scm_helper) - - # This did not exist before 3.4, but since then it is - # mandatory for our purpose - if hasattr(os, 'set_inheritable'): - os.set_inheritable(self._qmp.get_sock_fd(), True) - if fd is not None: - os.set_inheritable(fd, True) - - fd_param = ["%s" % self._socket_scm_helper, - "%d" % self._qmp.get_sock_fd()] if file_path is not None: assert fd is None - fd_param.append(file_path) + fd = -1 + try: + fd = os.open(file_path, os.O_RDONLY) + self._qmp.send_fd(fd) + except OSError: + return 1 + finally: + if fd != -1: + os.close(fd) else: assert fd is not None - fd_param.append(str(fd)) + try: + self._qmp.send_fd(fd) + except OSError: + return 1 - proc = subprocess.run( - fd_param, - stdin=subprocess.DEVNULL, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - check=False, - close_fds=False, - ) - if proc.stdout: - LOG.debug(proc.stdout) - - return proc.returncode + return 0 @staticmethod def _remove_if_exists(path: str) -> None: diff --git a/python/qemu/qmp/__init__.py b/python/qemu/qmp/__init__.py index 269516a79b..27a3e8f7af 100644 --- a/python/qemu/qmp/__init__.py +++ b/python/qemu/qmp/__init__.py @@ -17,6 +17,7 @@ # This work is licensed under the terms of the GNU GPL, version 2. See # the COPYING file in the top-level directory. +import array import errno import json import logging @@ -421,3 +422,17 @@ def is_scm_available(self) -> bool: @return True if SCM_RIGHTS is available, otherwise False. """ return self.__sock.family == socket.AF_UNIX + + def send_fd(self, fd: int) -> None: + """ + Send a file descriptor to QEMU via SCM_RIGHTS. + + @param fd (int): file descriptor do be sent + + @raise OSError: if the sendmsg system call fails. + """ + # Send a single space so that QEMU looks at the ancillary data + self.__sock.sendmsg((b" ", ), + [(socket.SOL_SOCKET, + socket.SCM_RIGHTS, + array.array("i", [fd]).tobytes())]) -- 2.31.1