From 32cbc59ba93eed4e5d09b7a6b5c3f7edf80c5c5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?= Date: Fri, 7 Dec 2018 04:22:05 +0100 Subject: [PATCH] tools/qvm-run: handle Ctrl+C nicely Do not exit with ugly python backtrace, simply interrupt the command (propagate SIGINT) and exit. QubesOS/qubes-issues#4532 --- qubesadmin/tools/qvm_run.py | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/qubesadmin/tools/qvm_run.py b/qubesadmin/tools/qvm_run.py index 47ed33f..39fc827 100644 --- a/qubesadmin/tools/qvm_run.py +++ b/qubesadmin/tools/qvm_run.py @@ -19,7 +19,9 @@ # with this program; if not, see . ''' qvm-run tool''' +import contextlib import os +import signal import subprocess import sys @@ -114,13 +116,16 @@ def copy_stdin(stream): # multiprocessing.Process have sys.stdin connected to /dev/null, use fd 0 # directly while True: - # select so this code works even if fd 0 is non-blocking - select.select([0], [], []) - data = os.read(0, 65536) - if data is None or data == b'': + try: + # select so this code works even if fd 0 is non-blocking + select.select([0], [], []) + data = os.read(0, 65536) + if data is None or data == b'': + break + stream.write(data) + stream.flush() + except KeyboardInterrupt: break - stream.write(data) - stream.flush() stream.close() def main(args=None, app=None): @@ -205,7 +210,12 @@ def main(args=None, app=None): if args.gui and not args.dispvm: wait_session = vm.run_service('qubes.WaitForSession', stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) - wait_session.communicate(vm.default_user.encode()) + try: + wait_session.communicate(vm.default_user.encode()) + except KeyboardInterrupt: + with contextlib.suppress(ProcessLookupError): + wait_session.send_signal(signal.SIGINT) + break if args.service: service = args.cmd else: @@ -239,8 +249,15 @@ def main(args=None, app=None): sys.stdout.flush() vm.log.error(str(e)) return -1 - for proc in procs: - retcode = max(retcode, proc.wait()) + try: + for proc in procs: + retcode = max(retcode, proc.wait()) + except KeyboardInterrupt: + for proc in procs: + with contextlib.suppress(ProcessLookupError): + proc.send_signal(signal.SIGINT) + for proc in procs: + retcode = max(retcode, proc.wait()) finally: if dispvm: dispvm.cleanup()