aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/manual.cli2
-rwxr-xr-xlogin-machine127
2 files changed, 129 insertions, 0 deletions
diff --git a/doc/manual.cli b/doc/manual.cli
index 91dc68b..a2484aa 100644
--- a/doc/manual.cli
+++ b/doc/manual.cli
@@ -592,6 +592,8 @@ command:
echo cont | ssh build@build socat - UNIX-CONNECT:/tmp/monitor-<toolchain>-<instance>
\
+\N|The \c{login-machine} helper script implements this sequence of steps.|
+
Other useful QEMU monitor commands are \c{system_powerdown} and
\c{system_reset}.
diff --git a/login-machine b/login-machine
new file mode 100755
index 0000000..18e1f34
--- /dev/null
+++ b/login-machine
@@ -0,0 +1,127 @@
+#! /usr/bin/env bash
+
+# Login into a machine.
+#
+# -c <monitor>
+# Execute QEMU 'cont' command in the specified machine monitor UNIX
+# socket prior to logging in.
+#
+# <host> - build host the machine is running on
+# <port> - machine's VNC port on the build host
+#
+usage="usage: $0 [-c <monitor>] <host> <port>"
+
+trap "{ exit 1; }" ERR
+set -o errtrace # Trap in functions.
+
+function info () { echo "$*" 1>&2; }
+function error () { info "$*"; exit 1; }
+
+mon=
+cmd=
+
+while [ "$#" -gt 0 ]; do
+ case "$1" in
+ -c)
+ shift
+ cmd=cont
+ mon="$1"
+ shift
+ ;;
+ -*)
+ error "unknown option: $1"
+ ;;
+ *)
+ break
+ ;;
+ esac
+done
+
+host="$1"
+fport="$2"
+
+if [ -z "$host" -o -z "$fport" ]; then
+ error "$usage"
+fi
+
+if [ -n "$cmd" -a -z "$mon" ]; then
+ error "$usage"
+fi
+
+# Find an unused local port. Surprisingly, it's harder than one would expect.
+#
+function find_used_ports ()
+{
+ # Use netstat(1) to find the list of port in use.
+ #
+ # Proto Recv-Q Send-Q Local Address Foreign Address State
+ # tcp 0 0 0.0.0.0:139 0.0.0.0:* LISTEN
+ #
+ local f="([^[:space:]]+)[[:space:]]+"
+
+ netstat --listening --all --tcp --numeric | \
+ sed -n -re "s/^$f$f$f$f.*$/\4/p" | \
+ sed -n -re "s/^.+:([0-9]+)$/\1/p" | \
+ sort --unique --numeric-sort
+}
+
+function find_unused_port ()
+{
+ local ups
+ ups=($(find_used_ports))
+
+ local lp up u
+ for ((lp=49152; lp < 65535; lp++)); do
+ u=
+ for up in "${ups[@]}"; do
+ if [ "$lp" -eq "$up" ]; then
+ u=true
+ break
+ fi
+ done
+
+ if [ ! "$u" ]; then
+ echo "$lp"
+ return 0
+ fi
+ done
+
+ echo "all ports are in use" 1>&2
+ return 1
+}
+
+lport=$(find_unused_port)
+
+# OpenSSH local port forwarding.
+#
+# ssh -L <localport>:<fowardhost>:<forwardport> <host>
+#
+# Forward connections on localhost:<localport> to <fowardhost>:<forwardport>
+# via <host>.
+#
+# We are putting OpenSSH to background (-f -N) and then using the "control
+# socket" mechanism (-M -S) to terminate it. This also makes sure we don't
+# share any existing control sockets that may be set in .ssh/config (e.g.,
+# for connection caching/multiplexing).
+#
+csock="$(mktemp -u)"
+
+ssh -f -N -M -S "$csock" -L "$lport:localhost:$fport" \
+ -o ExitOnForwardFailure=yes "build@$host"
+
+function exit_trap ()
+{
+ # OpenSSH prints "Exit request sent." regardless of -q.
+ #
+ if ! ssh -q -S "$csock" -O exit "build@$host" 2>/dev/null; then
+ error "unable to terminate background ssh process via $csock"
+ fi
+}
+
+trap exit_trap EXIT
+
+if [ -n "$cmd" ]; then
+ echo "$cmd" | ssh -S "$csock" "build@$host" socat - "UNIX-CONNECT:$mon"
+fi
+
+vinagre "localhost:$lport"