2015-03-07 10 views
8

Yerel bir x/crypto/ssh kitaplığını kullanarak SSH aracılığıyla bir ana bilgisayara bağlanacak ve bir interaktif kabuk bırakacak bir Go programı yazıyorum.Terminal kaçış dizilerini Go ile SSH'den nasıl gönderebilirim?

RequestPty() kullanıyorum, ancak uzak uçtaki (bash) kabuğu, denetim kodlarında beklendiği gibi davranmıyor.

Çeşitli denetim karakterleri girmek

, onlar benim terminali tarafından geri yankılandı ediyoruz:

$ ^[[A 

karakterden hala eser anlamda ben yukarı ok bastıktan sonra enter tuşuna değilse, önceki komut çalıştırılır - ancak kontrol karakteri çıkışı, orada nelerin görüntülenmesi gerektiğini gösterir. Aynı sekme için de geçerli.

Bunu işe almak için bazı kolay yol var mı? Geçmişte benzer sistemler kurduğumda bu bir sorun olmamıştı çünkü openssh'a bağlandım ve süreç gruplarının semantikleri hepsini çözdü.

"The TTY Demystified" üzerinde çalıştım ve bunun nereden başlayacağı net değil.

bunu araştırmak için düşündüm birkaç şey:

openssh kendisi

  • doğru bu işi yapıyor olmalı, ama bu çalışma bir kod tabanının gerçek en iyisidir.

    Bu yazdırma işleminin yerel terminal öykünücüsü veya kabuk veya uzak ana bilgisayardaki kod tarafından yapılıp yapılmadığı bana açık değil.

    Nereden başlamalıyım? screen-256color ve vt100: Ben terim değerlerinden diğer xterm daha bu denedim

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

    : Burada


    benim kod bir örnektir. Kayıt için

    - Gerçek kodda yerine session.Wait() için sadece bir çağrının, ben sürecine çeşitli sinyaller yakalar ve Session onları üzerinde gönderen bir for/select döngü var.

  • +3

    'ECHOCTL' terminal modunu devre dışı bırakmayı denediniz mi? –

    +0

    @EmilDavtyan bunu çözdü! Şimdi nedenini anlamak için. – Cera

    +1

    @Cerales Lütfen kendi sorunuzu cevaplamayı ve cevabı kabul etmeyi unutmayın :) – user918176

    cevap

    1

    ECHOCTL terminal modunu devre dışı bırakın.

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

    Bu, benim için çalışmaz. Hala karakter çıkış kodlarını görüyorum ve otomatik tamamlama çalışmıyor. – aramadia

    +0

    Kodumda ssh.ECHOCTL değerini 0 olarak ayarlıyorum ve ok tuşlarını kullandığımda hala kontrol karakterlerini görüyorum. Herhangi bir fikir? –

    6

    ssh.ECHO: 0 ve ssh.ECHOCTL: 0 ayarları benim için çalışmadı.Bu sorunla karşılaştım diğer insanlar için, aşağıdaki bunun Git ssh kütüphanesi ile tam çalışan interaktif terminali almak için geçen kaba kodudur:

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

    Not tüm klavye işlevselliği (yukarı ok sekme tamamlama,) ve sinyal işleme (CTRL + C, CTRL + D) yukarıdaki kurulumla doğru şekilde çalışıyor.

    +0

    Günümü kaydettiniz – ukautz

    +0

    Yani temelde problem şu ki 'os.Stdin' bir şekilde tamponlanıyor? Bu btw için teşekkürler, bu sorunun nasıl çözüleceğini anlamaya çalışırken gerçekten sinirli oluyordum. –