Make qvm-run bidirectional and document its limitations.

This commit is contained in:
Matt McCutchen 2015-02-07 19:10:25 -05:00 committed by Marek Marczykowski-Górecki
parent 377e0b4cd4
commit b37d391f91
2 changed files with 57 additions and 6 deletions

View File

@ -1,4 +1,45 @@
#!/bin/sh
# pass aguments to the remote stdin, shovel back the remote output
echo "$@"
exec /bin/cat >&$SAVED_FD_1
#!/usr/bin/python
# Send the command to the remote side, and then transfer stdin from local to
# remote and stdout from remote to local.
#
# The tricky part is delimiting the command from the stdin data. If we were
# implementing this from scratch, we'd probably use a null byte. However, we'd
# like to work with the existing qubes.VMShell service, whose implementation is
# simply "/bin/bash", so users don't have to maintain duplicate RPC policy. We
# take advantage of the fact that when bash is executing commands from a pipe,
# it reads one character at a time until it gets a newline that ends a command.
# So the initial qubes.VMShell bash process, which is executing commands from
# stdin, consumes exactly the line from the "write" below and then either
# completes the "exec" or exits. In no event does it touch the stdin data
# intended for the command.
import os
import subprocess
import sys
cmd = ' '.join(sys.argv[1:])
sys.stdout.write("exec bash -c '%s' || exit 127\n" % cmd.replace("'", "'\\''"))
sys.stdout.flush()
local_stdin = int(os.environ['SAVED_FD_0'])
local_stdout = int(os.environ['SAVED_FD_1'])
stdin_sender = subprocess.Popen(['cat'], stdin=local_stdin)
stdout_receiver = subprocess.Popen(['cat'], stdout=local_stdout)
# sys.std{in,out}.close() do not close the FDs, but they apparently stop Python
# from trying to close the FDs again on exit and generating an exception.
sys.stdin.close()
sys.stdout.close()
os.close(0)
# The really important step, so this process doesn't prevent qrexec-client-vm
# from seeing EOF on input.
os.close(1)
os.close(local_stdin)
os.close(local_stdout)
stdout_receiver.wait()
# With the current Qubes RPC implementation, the stdout receiver doesn't get EOF
# until the remote process has exited. At that point, we want to finish and not
# try to send more input. This is the same behavior ssh appears to have.
stdin_sender.terminate()
stdin_sender.wait()

View File

@ -21,8 +21,18 @@
#
if [ $# -lt 2 ] ; then
echo "Usage: $0 vmname command arguments"
echo " you can use \$dispvm or --dispvm instead of vmname to start new DisposableVM"
cat <<USAGE
Usage: $0 vmname command arguments
Executes a command in another VM using the qubes.VMShell RPC service. The
arguments are joined with spaces and passed to "bash -c".
Standard input and output are connected to the command. Unlike qvm-run in Dom0,
this tool does not propagate standard error or exit codes, nor does it offer
protection against the remote VM messing with your terminal if standard output
is your terminal.
You can use \$dispvm or --dispvm instead of vmname to start a new DisposableVM.
USAGE
exit 1
fi
VMNAME=$1