34

When all you have is a serial console (say via telnet through a terminal server), what methods can be used to transfer files in/out of a host?

Cut/paste works for the small/printable stuff and I've played with a combination of uuencode/uudecode (with gzip) handle the unprintable but it's all very limiting.

Caleb
  • 70,105

6 Answers6

19

The serial console programs¹ you'll use on the other end of the connection will have some way to send a file to the remote side. How exactly you go about it depends on what resources you have available on the remote system.

I Have lrzsz or kermit on the Remote Side

The easiest case is if you have a solid binary file transfer program installed on the remote side such as lrzsz or kermit. This was once more common than today, but your particular system might still have one of these.

The serial console program you're using on the local side almost certainly has a way to do a Zmodem or Kermit upload, which lets you send whatever you need directly.

In the case of Zmodem, just type rz on the remote system, which sends out a special string that the local serial terminal should understand, causing it to pop up a file picker dialog.

Kermit is a simpler protocol, so you have to start the transfer manually in that case.

I Don't Have a Binary File Transfer Program, but I Do Have uuencode/base64

There are several advantages to using a proper binary file transfer program like lrzsz or kermit: efficiency, checksumming, automatic retries, aborted transfer resumption, multiple file transfer, etc., but these are luxuries. If you only need to send one file, or you're sending files rarely, you can get away with ASCII uploads.

Because terminal protocols interpret many of the byte values that occur in a binary data file, you can't send the file directly through the same connection; if you do, the terminal emulation code on either end will try to interpret some of the data, corrupting the data and likely confusing the terminal handling code as well.

You get around this by encoding the binary data into a safe subset of ASCII on the local side, then turning it back into raw binary data on the remote side. This is what the uuencode and base64 programs do, differing only in minor algorithm choices.

On the local system, you encode the file:²

$ uuencode -o sbf.uue some-binary-file.gz some-binary-file.gz

Then you type this command on the remote system, and send the file using the local serial console's "ASCII upload" feature:

$ cat | uudecode

When the file upload finishes, hit Ctrl-C to get out of cat. Now you have your decoded file on the remote system, as you wanted.

But I Have Many Files to Send, and Printable ASCII Transcoding Is a Pain!

It is not hard to bootstrap yourself up to a higher level of technology. If the remote system has a C compiler, you can use the prior technique to send the remote system a copy of the lrzsz source code. On the local side:

$ uuencode -o lrzsz.tgz.uue lrzsz-0.12.20.tar.gz lrzsz-0.12.20.tar.gz

Then on the remote system, type this via the serial console program:

$ cat | uudecode
^C
$ tar xvf lrzsz-0.12.20.tar.gz
...build lrzsz normally

After you start the first command, do an "ASCII upload" of the lrzsz.tgz.uue file to the remote system. The pipeline accepts the uuencoded data and decodes it to a binary tarball for you, which you can unpack and build.

But I Don't Have a C Compiler on the Remote System

If you don't even have a compiler on the remote system, you can cross-compile the rz (or whatever) program on the local system and send it to the remote system using the above technique.


Footnotes:

  1. minicom, picocom, PuTTY, VanDyke CRT...

  2. You have to give the input file name to this version of uuencode twice, once to name the source of the input data, and again to declare what the remote system should call the file when it decodes the data to an output file. You could conceivably want the remote system to have a different name for its output file.

    Your local version of uuencode may behave differently.

Warren Young
  • 72,032
  • Fantastic, I was hoping this question had an answer mentioning kermit! +1 ;) – Tim Jun 15 '12 at 14:44
  • This is good answer, I like those "But I Don't Have" section. Unfortunately, it stops at quite pop stuff and doesn't go really deep. Creating binary executable files for different architectures from only ASCII codes anyone? Here's for bootstrap: https://retrocomputing.stackexchange.com/questions/4672/executable-ascii-files-before-x86 – pfalcon Sep 23 '18 at 21:09
9

Basically you have to use pre-internet methods to transfer over a serial tty, and you must have a way to receive the transfer on the other side. Obviously the best way to do this is by using ZMODEM, which means you need to have a tool like sz already on the receiving end. However this isn't always possible, for example, when the receiving target is a router without a network.

The only possible way to do this transfer is directly over the channel, using terminal safe ASCII, in pre-8-bit clean style. I'm going to use more modern tools, that I'd hope are installed on most systems.

Sender:

First we encode our file

base64 file.tar.gz > file.tar.gz.b64

Now make sure your com send-file command is, ascii-xfr, this was my connection command line

picocom -f n -p n -d 8 -b 115200  --send-cmd "ascii-xfr -snv" /dev/ttyS0

Normally we want ascii-xfr on the receiving side, but since we don't have it, that -n works around this by maintaining correct line endings.

Receiver:

Now that we've connected, go to the directory where you want the received file.

cd /tmp/
cat > file.tar.gz.b64

On picocom, I just CTRL+a+s, and enter the full path of the file I'm sending. Once the transfer completes, you'll need to CTRL+c to break that cat.

Now we decode the file,

base64 -d file.tar.gz.b64 > file.tar.gz

Do whatever you can to verify that file is IDENTICAL to the one you sent, because an ASCII transfer has no checksum protection. My receiving box had sha512sum, but any checksum command would suffice. Once you manually confirm the sums match, you can assume the transfer was successful!

J. M. Becker
  • 4,891
  • (And two years later...) in my experience having to transfer files across systems that munge line endings (thanks Microsoft!), base64 encoding/decoding doesn't care about line ending style. \r\n or just \n both work even if they get "fixed" along the way. I don't recall offhand if that's in the base64 standard or just the tools I used, but I suspect it's actually standard behavior. – Andrew Henle Sep 23 '18 at 22:15
  • I didn't have base64 (or uudecode) available on the remote system, and found a blog post showing how to do the ascii2binary manually. Additionally, the remote ash/BusyBox would ignore the Ctrl+C, so I set a termination timer for after the transfer is done: $(sleep 60 && killall tee) &, then receive using tee instead of cat: tee file.tar.gz.b64 – argonym Oct 16 '21 at 15:49
  • On Linux Ubuntu, install ascii-xfr with sudo apt install minicom. – Gabriel Staples Oct 06 '22 at 16:52
  • @AndrewHenle, the man page says it always transfers CRLF, but the CR gets stripped on receive. I'm not sure what causes that to happen, but I wouldn't be surprised if it was somehow an implementation detail of reading an stdio stream. http://rpm.pbone.net/manpage_idpl_2391192_numer_1_nazwa_ascii-xfr.html – J. M. Becker Nov 08 '22 at 16:32
5

Don't know if this would work if all you had was a serial console, but if you have network access at all, then you could use nc(1) to copy files using TCP/IP.

# WARNING: Depending on your setup, this could make your system unbootable
root@destination-box.local # nc -l 8675 | dd of=/dev/sdXXX
root@source-box.local # dd if=/dev/sdYYY | nc destination-box.local 8675

In the above example, I cloned sdbYYY from a source box to sdaXXX of the destination box. My choice of 8675 for a TCP port number was arbitrary; you could use any port you have access to. And it doesn't have to be a device; it can be any file.

kevin@destination-box.local $ nc -l 12345 >> ~/.ssh/authorized_keys
kevin@source-box.local $ cat ~/.ssh/id_rsa.pub | nc destination-box.local 12345

In the second example, I copied my rsa public key (~/.ssh/id_rsa.pub) and added it to the authorized keys file for the target host.

Kevin M
  • 1,973
  • 5
    Might I suggest a big red warning sign above your first idea? Some lonely soul with the heart to learn might execute something like that in the hopes of copying just files, without reading the following paragraph first of course :) – reiche Aug 11 '10 at 17:36
4

Maybe you should give minicom a try.

Phidelux
  • 133
elmarco
  • 1,434
  • 1
  • 14
  • 13
  • 1
    Doesn't this require something like 'sx' or 'sz' on the source host? – Stephen Paul Lesniewski Aug 11 '10 at 17:19
  • 4
    Nope, minicom handles its own file xfers. sx,sy,sz and rx,ry,rz are separate programs, usually found in packages aptly named lszrz or something. Though I would suggest using sz and rz. Small, simple and it does what it does. Minicom is a whole terminal emulator. – reiche Aug 11 '10 at 17:34
  • 6
    This answer is not correct. Minicom spawns lrzsz for file transfers. Minicom can not and does not handle it's own file transfers. – Jonathan Cline IEEE Sep 02 '11 at 17:50
  • not an answer. how exactly should i send a file using minicom? – BЈовић Jun 22 '23 at 12:42
2

I would use kermit, the grandparent of filetransfer programs. We used that already long before there was Linux.

txwikinger
  • 2,226
  • 22
  • 27
0

My way of transferring a file.bin via serial connection is to use openSSL tool since I don't have other options to do base64 encoding and back:

openssl enc -base64 <file.bin > file.b64

Decode:

openssl enc -base64 -d <file.b64 > file.bin
  • 1
    Welcome to the site, and thank you for your contribution. You may want to edit your post to include more instructions on how you actually transfer the base64-encoded file via the serial console, as this may also be unkown to many readers of this question. – AdminBee Apr 28 '20 at 07:27