14

I need to send some special keystrokes and am unsure of how to do it.

I need to send Ctrl + Q followed by Ctrl + A to a terminal (I'm using Paramiko).

i have tried

shell = client.invoke_shell()

shell.send(chr(10))
time.sleep(5)
shell.send(chr(13))

shell.send('\x11')
shell.send('\x01')

print 'i tried'

I can see the two returns go in successfully, but then nothing, it doesnt quit the picocom (also to note i have it the wrong way round, its expecting ctrl+a, then ctrl+q)

if it helps this is the device http://www.cisco.com/c/en/us/td/docs/routers/access/interfaces/eesm/software/configuration/guide/4451_config.html#pgfId-1069760

as you can see at step 2

Step 2 Exit the session from the switch, press Ctrl-a and Ctrl-q from your keyboard:

Switch# <type ^a^q>
Thanks for using picocom
Router#

UPDATE:

i have tried \x01\x16\x11\n but this returns

Switch#
Switch#
*** baud: 9600
*** flow: none
*** parity: none
*** databits: 8
*** dtr: down

Switch#

this looks like it could be another special command?

AlexW
  • 2,843
  • 12
  • 74
  • 156
  • Those kind of signals are rather received by applications (than sent). For what reason do you need them? Probably there is another way to work around. – a_guest Mar 28 '16 at 02:23
  • im creating a script to build a cisco config, and the router has an internal module that uses picocom, ones ive set up the config via picocom, the keys ctrl + a, then q exits picocom so i can run the rest of my script – AlexW Mar 29 '16 at 08:13

3 Answers3

6

Pressing Ctrl + key is actually a "user-friendly" way to enter ASCII control characters. This is done by subtracting 64 from the ASCII code of the entered key (taking the capital letter where applicable). The combination Ctrl + H, for example, is equivalent to entering a backspace (H has code 72, 72-64=8, the backspace character). This Wikipedia page lists the ASCII control characters associated with their key combinations, so Ctrl+A, Ctrl+Q is equivalent to sending the string "\x01\x11" through the paramiko Channel:

channel = client.invoke_shell()
channel.send('\x01\x11')

Update

To check what is actually transmitted when I press Ctrl+A Ctrl+Q I have devised a small test program:

# decode.py
import sys

while True:
    inp = sys.stdin.read(1)
    if len(inp) == 0:
        break
    print ord(inp[0])

If I now call this via ssh localhost python decode.py and enter Ctrl+A Ctrl+V Ctrl+Q (i have to do the Ctrl+V because Ctrl+Q is interpreted as XON by my local shell and not passed on to the other side), then Enter Ctrl+D to close the connection, i get 1, 17 and 10 as ordinals, or '\x01\x11\n', as expected.

I basically get the same by executing printf '\x01\x11\n' | ssh localhost python decode.py. If, however, I allocate a pty on the remote end via printf '\x01\x11\n' | ssh -tt localhost python decode.py the \x11 is intercepted by the remote pty and not passed on through to the running script (i get 1,10 as output). In this case it helps to send a Ctrl+V (\x16) before the Ctrl+Q that instructs the pty to pass the next character Verbatim. As expected printf '\x01\x16\x11\n' | ssh -tt localhost python decode.py outputs 1, 17 and 10.

Community
  • 1
  • 1
Roland W
  • 1,401
  • 14
  • 21
5

Just as assumption: maybe pseudoterminal would help

import paramiko
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(...)
channel = сlient.get_transport().open_session()
channel.get_pty()
channel.settimeout(5)
channel.exec_command('\x11\x01') 
Alexey Smirnov
  • 2,573
  • 14
  • 20
  • this gives me " Non-ASCII character '\xd1' in file paramiko_test.py on line 20, but no encoding declared" – AlexW Apr 04 '16 at 10:08
5

This works perfectly for me, returning exactly what I would expect. There are obviously some pieces missing from your code above, so this required a little winging.

import sys
import time
import getpass
import paramiko

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect('127.0.0.1',
            username='apsuser',
            password=getpass.getpass('Password: '))
shell = ssh.invoke_shell()
shell.settimeout(0.25)

shell.send('picocom /dev/ttyS0\n')
time.sleep(2)
sys.stdout.buffer.write(shell.recv(10000))
sys.stdout.buffer.flush()

shell.send('\x01')
shell.send('\x11')

time.sleep(2)
sys.stdout.buffer.write(shell.recv(10000))
sys.stdout.buffer.flush()
print()
time.sleep(2)

And the results are:

Password: 

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Thu Apr 14 19:55:57 2016 from 127.0.0.1
picocom /dev/ttyS0
apsuser@Steve-Laptop:~$ picocom /dev/ttyS0
picocom v1.7

port is        : /dev/ttyS0
flowcontrol    : none
baudrate is    : 9600
parity is      : none
databits are   : 8
escape is      : C-a
local echo is  : no
noinit is      : no
noreset is     : no
nolock is      : no
send_cmd is    : sz -vv
receive_cmd is : rz -vv
imap is        : 
omap is        : 
emap is        : crcrlf,delbs,

Terminal ready

Thanks for using picocom
apsuser@Steve-Laptop:~$ 

So what did I do that your code does not do?

Steve Cohen
  • 722
  • 4
  • 6
  • this has worked, i think the problem was i was sending /n at the end, (sending the enter key with it!) whoops! – AlexW Apr 15 '16 at 08:23