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
This commit is contained in:
Marek Marczykowski-Górecki 2018-12-07 04:22:05 +01:00
parent 9acce13a35
commit 32cbc59ba9
No known key found for this signature in database
GPG Key ID: 063938BA42CFA724

View File

@ -19,7 +19,9 @@
# with this program; if not, see <http://www.gnu.org/licenses/>. # with this program; if not, see <http://www.gnu.org/licenses/>.
''' qvm-run tool''' ''' qvm-run tool'''
import contextlib
import os import os
import signal
import subprocess import subprocess
import sys import sys
@ -114,13 +116,16 @@ def copy_stdin(stream):
# multiprocessing.Process have sys.stdin connected to /dev/null, use fd 0 # multiprocessing.Process have sys.stdin connected to /dev/null, use fd 0
# directly # directly
while True: while True:
# select so this code works even if fd 0 is non-blocking try:
select.select([0], [], []) # select so this code works even if fd 0 is non-blocking
data = os.read(0, 65536) select.select([0], [], [])
if data is None or data == b'': data = os.read(0, 65536)
if data is None or data == b'':
break
stream.write(data)
stream.flush()
except KeyboardInterrupt:
break break
stream.write(data)
stream.flush()
stream.close() stream.close()
def main(args=None, app=None): def main(args=None, app=None):
@ -205,7 +210,12 @@ def main(args=None, app=None):
if args.gui and not args.dispvm: if args.gui and not args.dispvm:
wait_session = vm.run_service('qubes.WaitForSession', wait_session = vm.run_service('qubes.WaitForSession',
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) 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: if args.service:
service = args.cmd service = args.cmd
else: else:
@ -239,8 +249,15 @@ def main(args=None, app=None):
sys.stdout.flush() sys.stdout.flush()
vm.log.error(str(e)) vm.log.error(str(e))
return -1 return -1
for proc in procs: try:
retcode = max(retcode, proc.wait()) 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: finally:
if dispvm: if dispvm:
dispvm.cleanup() dispvm.cleanup()