2015-03-07 56 views
8

Piszę program Go, który połączy się z hostem przez SSH, używając natywnej biblioteki x/crypto/ssh i usunie powłokę interpolowaną.Jak mogę wysłać sekwencje specjalne terminala przez SSH za pomocą Go?

Używam RequestPty(), ale powłoka (bash) na zdalnym końcu nie zachowuje się zgodnie z oczekiwaniami z kodami kontrolnymi.

Kiedy wprowadzić różne znaki sterujące, oni echo mojego terminalu:

$ ^[[A 

Znaki nadal pracy w tym sensie, że jeśli naciśnij enter po naciśnięciu strzałki w górę, poprzednia komenda jest uruchomione - ale wyjście z postaci sterującej blokuje to, co powinno być tam wyświetlane. To samo dotyczy zakładki.

Czy jest jakiś prosty sposób, aby to zadziałało? Kiedy już zaimplementowałem podobne systemy w przeszłości, nie było to problemem, ponieważ właśnie wyjąłem numer openssh, a semantyka grup procesów wszystko to uporządkuje.

Studiowałem "The TTY Demystified" i tak dobre, jak to jest nie wiadomo od czego zacząć.

Kilka rzeczy myślałem o zbadanie:

sobie openssh należy robić tę pracę poprawnie, ale to naprawdę najlepszy bazy kodu na studia.

Nie jest dla mnie jasne, czy ten wydruk jest wykonywany przez mój lokalny emulator terminalu lub powłokę, czy przez kod na zdalnym hoście.

Od czego zacząć?


Oto przykład z mojego kodu:

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() 

Próbowałem to z wartościami określony inny niż xterm: screen-256color i vt100.

Dla przypomnienia - w rzeczywistym kodzie, a nie tylko wezwanie do session.Wait() mam for/select pętlę, która łapie różne sygnały do ​​procesu i wysyła je do Session.

+3

Czy próbowałeś wyłączyć tryb terminala 'ECHOCTL'? –

+0

@EmilDavtyan to naprawił! Teraz, aby zrozumieć, dlaczego. – Cera

+1

@Cerales Pamiętaj, aby odpowiedzieć na własne pytanie i zaakceptować odpowiedź :) – user918176

Odpowiedz

1

Wyłącz tryb terminalu ECHOCTL.

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

To nie działa dla mnie. Nadal widzę kody ucieczki postaci i autouzupełnianie nie działa. – aramadia

+0

Ustawiłem 'ssh.ECHOCTL' na 0 w moim kodzie i nadal widzę znaki kontrolne, kiedy używam klawiszy strzałek. Jakieś pomysły? –

6

W ssh.ECHO: 0 i ssh.ECHOCTL: 0 ustawienia nie działa na mnie.Dla innych osób, które biegły w tej kwestii, poniżej jest szorstki kod zajęło aby uzyskać w pełni funkcjonalny interaktywny terminal z Go ssh Biblioteka:

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() 

pamiętać, że wszystkie funkcje klawiatury (zakończenie zakładka, strzałka w górę) i sygnał obsługa (CTRL + C, CTRL + D) działa poprawnie z powyższą konfiguracją.

+0

Uratowałeś mój dzień – ukautz

+0

Więc zasadniczo problem polega na tym, że 'os.Stdin' jest w jakiś sposób buforowany? Dzięki za btw, byłem naprawdę sfrustrowany próbując dowiedzieć się, jak rozwiązać ten problem. –