Make qvm-run bidirectional and document its limitations.
This commit is contained in:
parent
377e0b4cd4
commit
b37d391f91
@ -1,4 +1,45 @@
|
|||||||
#!/bin/sh
|
#!/usr/bin/python
|
||||||
# pass aguments to the remote stdin, shovel back the remote output
|
# Send the command to the remote side, and then transfer stdin from local to
|
||||||
echo "$@"
|
# remote and stdout from remote to local.
|
||||||
exec /bin/cat >&$SAVED_FD_1
|
#
|
||||||
|
# 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()
|
||||||
|
@ -21,8 +21,18 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
if [ $# -lt 2 ] ; then
|
if [ $# -lt 2 ] ; then
|
||||||
echo "Usage: $0 vmname command arguments"
|
cat <<USAGE
|
||||||
echo " you can use \$dispvm or --dispvm instead of vmname to start new DisposableVM"
|
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
|
exit 1
|
||||||
fi
|
fi
|
||||||
VMNAME=$1
|
VMNAME=$1
|
||||||
|
Loading…
Reference in New Issue
Block a user