2015-03-07 3 views
8

Я пишу программу Go, которая будет подключаться к хосту через SSH, используя собственную библиотеку x/crypto/ssh и отбрасывать оболочку.Как я могу отправить управляющие последовательности терминала через SSH с Go?

Я использую RequestPty(), но оболочка (bash) на удаленном конце работает не так, как ожидалось, с помощью управляющих кодов.

Когда вводить различные управляющие символы, они возвращаются назад на моем терминале:

$ ^[[A 

персонажей еще работы в том смысле, что, если нажать клавишу ВВОД после нажатия на стрелку вверх, предыдущая команда запускается - но вывод управляющего символа сжимает то, что должно отображаться там. То же самое касается вкладки.

Есть ли какой-нибудь простой способ заставить это работать? Когда я реализовал подобные системы в прошлом, это не было проблемой, потому что я только что обрезал до openssh, и семантика групп процессов разобрала все это.

Я изучил «The TTY Demystified» и так хорошо, как не ясно, с чего начать.

Несколько вещей, которые я думал исследовать:

openssh сам по себе должен делать эту работу правильно, но это настоящий лучший из кодовой базы для изучения.

На самом деле мне не ясно, выполняется ли эта печать моим локальным эмулятором терминала или оболочкой или кодом на удаленном хосте.

С чего начать?


Вот пример моего кода:

conf := ssh.ClientConfig{ 
    User: myuser, 
    Auth: []ssh.AuthMethod{ssh.Password(my_password)} 
} 
conn, err := ssh.Dial("tcp", myhost, conf) 
if err != nil { 
    return err 
} 
defer conn.Close() 
session, err := conn.NewSession() 
if err != nil { 
    return err 
} 
defer session.Close() 
session.Stdout = os.Stdout 
session.Stderr = os.Stderr 
session.Stdin = os.Stdin 

modes := ssh.TerminalModes{ 
    ssh.ECHO: 0 
    ssh.TTY_OP_ISPEED: 14400, 
    ssh.TTY_OP_OSPEED: 14400 
} 
if err := session.RequestPty("xterm", 80, 40, modes); err != nil { 
    return err 
} 
if err = session.Shell(); err != nil { 
    return err 
} 

return session.Wait() 

Я попытался это с долгосрочными значениями, отличные от xterm: screen-256color и vt100.

Для записи - в реальном коде, а не только призыв к session.Wait(), у меня есть for/select цикл, который улавливает различные сигналы процесса и отправляет их на к Session.

+3

Вы пытались отключить режим терминала ECHOCTL? –

+0

@ EmilDavtyan, который исправил это! Теперь, чтобы понять, почему. – Cera

+1

@Cerales Пожалуйста, не забудьте ответить на свой вопрос и принять ответ :) – user918176

ответ

1

Отключить ECHOCTL терминал режим.

modes := ssh.TerminalModes{ 
    ssh.ECHO: 0, 
    ssh.ECHOCTL: 0, 
    ssh.TTY_OP_ISPEED: 14400, 
    ssh.TTY_OP_OSPEED: 14400 
} 
+2

Это не работает для меня. Я по-прежнему вижу коды escape-кода персонажа, и автозаполнение не работает. – aramadia

+0

Я установил 'ssh.ECHOCTL' 0 в свой код и все еще вижу контрольные символы, когда я использую клавиши со стрелками. Есть идеи? –

6

В ssh.ECHO: 0 и ssh.ECHOCTL: 0 настройки не работает для меня.Для других людей, которые бежали в этот вопрос, ниже грубый код потребовалось, чтобы получить полностью рабочий интерактивный терминал с SSH библиотеки Go:

config := return &ssh.ClientConfig{ 
    User: "username", 
    Auth: []ssh.AuthMethod{ssh.Password("password")}, 
} 

client, err := ssh.Dial("tcp", "12.34.56.78:22", config) 
if err != nil { ... } 
defer client.Close() 

session, err := client.NewSession() 
if err != nil { ... } 
defer session.Close() 

session.Stdout = os.Stdout 
session.Stderr = os.Stderr 
session.Stdin = os.Stdin 

modes := ssh.TerminalModes{ 
    ssh.ECHO:   1,  // enable echoing 
    ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud 
    ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud 
} 

fileDescriptor := int(os.Stdin.Fd()) 

if terminal.IsTerminal(fileDescriptor) { 
    originalState, err := terminal.MakeRaw(fileDescriptor) 
    if err != nil { ... } 
    defer terminal.Restore(fileDescriptor, originalState) 

    termWidth, termHeight, err := terminal.GetSize(fileDescriptor) 
    if err != nil { ... } 

    err = session.RequestPty("xterm-256color", termHeight, termWidth, modes) 
    if err != nil { ... } 
} 

err = session.Shell() 
if err != nil { ... } 

// You should now be connected via SSH with a fully-interactive terminal 
// This call blocks until the user exits the session (e.g. via CTRL + D) 
session.Wait() 

Заметим, что все функции клавиатуры (автодополнению стрелка вверх) и сигнал (CTRL + C, CTRL + D) правильно работает с настройкой выше.

+0

Вы сохранили мой день – ukautz

+0

Итак, в основном проблема заключается в том, что 'os.Stdin' как-то буферизуется? Спасибо за это, я очень расстраивался, пытаясь понять, как решить эту проблему. –

 Смежные вопросы

  • Нет связанных вопросов^_^