fangxlmr
fangxlmr

Reputation: 29

Error transporting binary data over ssh/telnet (even shell) in expect script

It seems like no one is maintaining this repo and this repo any more.

Assuming I'd like to fetch data from remote with user/password auth automating in expect script, like the following: ps: I use sh to refer ssh/telnet connection

$ expect -v
expect vesion 5.45.4
$ cat expect.sh
#!/usr/bin/expect -f

spawn -noecho sh -c ./download.sh
interact
$ cat download.sh
#!/bin/sh

sh -c 'cat /bin/ls' # cat a binary file
$ ./expect.sh > a.out
$ file a.out
a.out: ELF 64-bit LSB shared object, x86-64, version1 (SYSV), too many program (2304)

As the last command said, captured command ls (i.e. a.out) has broken locally. And you can find if you actually run the script, the two files are different in bytesize (let alone checksum).

I though it might be related to traslation and encoding issue, so I change the expect.sh script to this and it still not working

$ cat expect.sh
#!/usr/bin/expect -f

spawn -noecho sh -c ./download.sh
fconfigure $spawn_id -translation binary -encoding binary
fconfigure stdin -translation binary -encoding binary
fconfigure stdout -translation binary -encoding binary
interact

Anybody has any idea?

Upvotes: 0

Views: 589

Answers (2)

meuh
meuh

Reputation: 12255

You should have more success if you set the tty to raw mode first. In expect this is done by setting global variable stty_init to the sort of string values you would give the stty command. For example,

set stty_init raw
log_user 0
spawn ssh user@host "cat /bin/ls; sleep 1"
expect assword: {send mypassword\r}
expect \n
log_user 1
expect eof

Direct the stdout of the above into a file and it should get just the contents of the ls file. Note how log_user 0 is used to suppress output until we have read past the \n newline. Also, I had to add a sleep after the cat otherwise the tty was closed before all the data was read and the file ended up a little shorter than the original. There should probably be a better way of doing that.

Upvotes: 0

pynexj
pynexj

Reputation: 20758

Usually dumping a binary file to tty would cause unexpected results. You can just try cat /bin/ls in an interactive shell and see what would happen. A tty is not a pass-through pipe. It does not output exactly what is sent to it.

See this simple example:

[STEP 101] # printf '\n'

[STEP 102] # printf '\n' | hexdump -C
00000000  0a                                                |.|
00000001
[STEP 103] #
[STEP 104] # expect -c 'spawn -noecho printf \n; expect eof'

[STEP 105] # expect -c 'spawn -noecho printf \n; expect eof' | hexdump -C
00000000  0d 0a                                             |..|
00000002
[STEP 106] #
[STEP 107] # expect -d -c 'spawn -noecho printf \n; expect eof'
expect version 5.45.4
parent: waiting for sync byte
parent: telling child to go ahead
parent: now unsynchronized from child
spawn: returns {57875}

expect: read eof
expect: set expect_out(spawn_id) "exp4"
expect: set expect_out(buffer) "\r\n"
argv[0] = expect  argv[1] = -d  argv[2] = -c  argv[3] = spawn -noecho printf \n; expect eof
set argc 0
set argv0 "expect"
set argv ""
[STEP 108] #

As you can see, \n is converted to \r\n when outputted to the tty.

Upvotes: 1

Related Questions