package terminal import ( "fmt" "github.com/creack/pty" "github.com/gliderlabs/ssh" "io" "os" "os/exec" "syscall" "unsafe" ) var PtySpawner = Spawner(func(sshSession ssh.Session, env []string, name string, arg ...string) (Process, error) { cmd := exec.Command(name, arg...) ptyReq, winCh, isPty := sshSession.Pty() if !isPty { return nil, fmt.Errorf("ssh session is not a pty") } cmd.Env = append(env, fmt.Sprintf("TERM=%s", ptyReq.Term)) f, err := pty.Start(cmd) if err != nil { return nil, err } go func() { for win := range winCh { setWinsize(f, win.Width, win.Height) } }() return ptyProcess{cmd: cmd, f: f}, nil }) func setWinsize(f *os.File, w, h int) { syscall.Syscall(syscall.SYS_IOCTL, f.Fd(), uintptr(syscall.TIOCSWINSZ), uintptr(unsafe.Pointer(&struct{ h, w, x, y uint16 }{uint16(h), uint16(w), 0, 0}))) } type ptyProcess struct { cmd *exec.Cmd f *os.File } func (p ptyProcess) Pipe() io.ReadWriter { return p.f } func (p ptyProcess) Kill() error { return p.cmd.Process.Kill() } func (p ptyProcess) Wait() error { return p.cmd.Wait() }