Skip to content

Instantly share code, notes, and snippets.

@rickardp
Created December 13, 2014 17:03
Show Gist options
  • Save rickardp/08b513e55ac5edd56caa to your computer and use it in GitHub Desktop.
Save rickardp/08b513e55ac5edd56caa to your computer and use it in GitHub Desktop.
Busybox file copy tool
#!/usr/bin/python
#
# Tool to copy files/directory trees to/from devices where the only opening
# is a telnet/serial shell and there is nothing other than a basic busybox on the device.
#
import sys, socket, tempfile, shutil, re, time
import telnetlib as T
# Busybox telnetd always expands tabs to spaces (this is hard-coded into telnetd.c)
XTABS_WORKAROUND = True
prompt = None
def expect(s, r, to=1000):
buf = ""
t0 = time.time()
while (not r) or (not buf.endswith(r)):
l = s.recv(4096)
if len(l) == 0: break
buf += l
if time.time() - t0 > to: break
return buf
# Expand / unexpand telnet IAC chars
def escape(s):
return s.replace("\xff", "\xff\xff")
def unescape(s):
return s.replace("\xff\xff", "\xff")
def do_cmd(s, cmd, stdin=False, stdout=False):
cmd = escape(cmd).strip()
if XTABS_WORKAROUND and stdout:
cmd += ' | sed "s/#/##/g" | sed "s/\\t/#t/g"'
cmd += '\r\n'
print >>sys.stderr, ">>", cmd,
s.send(cmd)
if stdin:
raise NotImplementedError()
buf = unescape(expect(s, prompt))
if buf.startswith(cmd): buf = buf[len(cmd):]
if buf.endswith(prompt): buf = buf[:-len(prompt)]
if XTABS_WORKAROUND and stdout:
buf = buf.replace("#t","\t").replace("##","#")
buf = buf.replace("\r\n", "\n")
l = []
return buf
def usage():
print >>sys.stderr, "Usage: " + sys.argv[0] + " <dest> [getdir|get|putdir|put] <remotefile>"
print >>sys.stderr, "Last-resort binary transfer when the only access is telnet or a"
print >>sys.stderr, "serial console. When possible, use ssh/scp instead of this hack."
print >>sys.stderr, ""
print >>sys.stderr, "Local file is always stdin/stdout"
print >>sys.stderr, "Examples:"
print >>sys.stderr, " " + sys.argv[0] + " 192.168.1.121 getdir / > rootfs.tar.gz"
print >>sys.stderr, " (Gets entire filesystem as tarball over telnet)"
print >>sys.stderr, " " + sys.argv[0] + " /dev/ttyUSB0 get /dev/mmcblk0p1 > part0.gz"
print >>sys.stderr, " (Gets block device as gzip over serial)"
print >>sys.stderr, " " + sys.argv[0] + " /dev/ttyUSB0 put /bin/ls < hacked_ls"
print >>sys.stderr, " (Replaces /bin/ls over serial)"
def do_connect(dest):
global prompt
hp = dest.split(":")
port = 23
if len(hp) > 1:
port = int(hp[1])
# Connect
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((hp[0], port))
# Wait for prompt
buf = expect(s, r"# ", .5)
prompt = buf.split("\n")[-1]
return s
def do_getdir(dest, remotefile):
s = do_connect(dest)
buf = do_cmd(s, 'tar -zc -C ' + remotefile + ' . 2>/dev/null', stdout=True)
sys.stdout.write(buf)
s.close()
def do_get(dest, remotefile):
s = do_connect(dest)
buf = do_cmd(s, 'gzip 2>/dev/null < ' + remotefile, stdout=True)
sys.stdout.write(buf)
s.close()
def do_put(dest, remotefile):
s = do_connect(dest)
buf = do_cmd(s, 'cat > ' + remotefile, stdin=True)
sys.stdout.write(buf)
s.close()
def do_putdir(dest, remotefile):
raise NotImplementedError("putdir command is not implemented")
if __name__ == '__main__':
if len(sys.argv) <= 3:
usage()
sys.exit(1)
dest = sys.argv[2]
remotefile = sys.argv[3]
if sys.argv[1] == "getdir":
do_getdir(dest, remotefile)
elif sys.argv[1] == "get":
do_get(dest, remotefile)
elif sys.argv[1] == "putdir":
do_putdir(dest, remotefile)
elif sys.argv[1] == "put":
do_put(dest, remotefile)
else:
print >>sys.stderr, "Sub-command", sys.argv[1], "not recognized"
usage()
sys.exit(1)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment