aboutsummaryrefslogtreecommitdiff
path: root/login-machine
blob: 18e1f3405470d07309ef998e79a3c2dc1dcb72e6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
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"