1#!/usr/bin/env python
2#
3# Usage: bootstrap_client.py <address>[:port] <command> ...
4#
5# <command> and the following arguments are concatenated (separated by a space)
6# and passed to a shell on the server.
7
8import os
9import select
10import socket
11import sys
12
13
14port = 4242
15bufferSize = 4 * 1024
16
17# interpret command line args
18if len(sys.argv) < 3:
19	sys.exit('Usage: ' + sys.argv[0] + ' <address>[:<port>] <command>')
20
21address = sys.argv[1]
22portIndex = address.find(':')
23if portIndex >= 0:
24	port = int(address[portIndex + 1:])
25	address = address[:portIndex]
26
27commandToRun = " ".join(sys.argv[2:])
28
29# create sockets and connect to server
30controlConnection = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
31stdioConnection = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
32stderrConnection = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
33
34try:
35	controlConnection.connect((address, port))
36	stdioConnection.connect((address, port))
37	stderrConnection.connect((address, port))
38except socket.error, msg:
39	sys.exit('Failed to connect to %s port %d: %s' % (address, port, msg[1]))
40
41# send command length and command
42controlConnection.send("%08d" % len(commandToRun))
43controlConnection.send(commandToRun)
44
45# I/O loop. We quit when all sockets have been closed.
46exitCode = ''
47connections = [controlConnection, stdioConnection, stderrConnection, sys.stdin]
48
49while connections and (len(connections) > 1 or not sys.stdin in connections):
50	(readable, writable, exceptions) = select.select(connections, [],
51		connections)
52
53	if sys.stdin in readable:
54		data = sys.stdin.readline(bufferSize)
55		if data:
56			stdioConnection.send(data)
57		else:
58			connections.remove(sys.stdin)
59			stdioConnection.shutdown(socket.SHUT_WR)
60
61	if stdioConnection in readable:
62		data = stdioConnection.recv(bufferSize)
63		if data:
64			sys.stdout.write(data)
65		else:
66			connections.remove(stdioConnection)
67
68	if stderrConnection in readable:
69		data = stderrConnection.recv(bufferSize)
70		if data:
71			sys.stderr.write(data)
72		else:
73			connections.remove(stderrConnection)
74
75	if controlConnection in readable:
76		data = controlConnection.recv(bufferSize)
77		if data:
78			exitCode += data
79		else:
80			connections.remove(controlConnection)
81
82# either an exit code has been sent or we consider this an error
83if exitCode:
84	sys.exit(int(exitCode))
85sys.exit(1)
86